Skip to content

Commit

Permalink
Create a QbftMetricsService (hyperledger#1861)
Browse files Browse the repository at this point in the history
Enables QBFT metrics to be exported to an API for reading via a plugin.

Signed-off-by: Trent Mohay <[email protected]>
  • Loading branch information
rain-on authored Feb 2, 2021
1 parent 78f5203 commit 08615f2
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.controller;

import org.hyperledger.besu.consensus.common.BlockInterface;
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.queries.BftQueryServiceImpl;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.plugin.services.metrics.PoAMetricsService;
import org.hyperledger.besu.plugin.services.query.BftQueryService;
import org.hyperledger.besu.plugin.services.query.PoaQueryService;
import org.hyperledger.besu.services.BesuPluginContextImpl;

public class BftQueryPluginServiceFactory implements PluginServiceFactory {

private final Blockchain blockchain;
private final NodeKey nodeKey;
private final String consensusMechanismName;

public BftQueryPluginServiceFactory(
final Blockchain blockchain, final NodeKey nodeKey, final String consensusMechanismName) {
this.blockchain = blockchain;
this.nodeKey = nodeKey;
this.consensusMechanismName = consensusMechanismName;
}

@Override
public void appendPluginServices(final BesuPluginContextImpl besuContext) {
final BlockInterface blockInterface = new BftBlockInterface();

final BftQueryServiceImpl service =
new BftQueryServiceImpl(blockInterface, blockchain, nodeKey, consensusMechanismName);
besuContext.addService(BftQueryService.class, service);
besuContext.addService(PoaQueryService.class, service);
besuContext.addService(PoAMetricsService.class, service);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

import org.hyperledger.besu.consensus.common.BlockInterface;
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.queries.BftQueryServiceImpl;
import org.hyperledger.besu.consensus.ibft.queries.IbftQueryServiceImpl;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.plugin.services.metrics.PoAMetricsService;
import org.hyperledger.besu.plugin.services.query.BftQueryService;
import org.hyperledger.besu.plugin.services.query.IbftQueryService;
import org.hyperledger.besu.plugin.services.query.PoaQueryService;
import org.hyperledger.besu.services.BesuPluginContextImpl;
Expand All @@ -43,5 +45,9 @@ public void appendPluginServices(final BesuPluginContextImpl besuContext) {
besuContext.addService(IbftQueryService.class, service);
besuContext.addService(PoaQueryService.class, service);
besuContext.addService(PoAMetricsService.class, service);

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

@Override
protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) {
return new NoopPluginServiceFactory();
return new BftQueryPluginServiceFactory(blockchain, nodeKey, "qbft");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.consensus.common.bft.queries;

import org.hyperledger.besu.consensus.common.BlockInterface;
import org.hyperledger.besu.consensus.common.PoaQueryServiceImpl;
import org.hyperledger.besu.consensus.common.bft.BftBlockHashing;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.plugin.data.Address;
import org.hyperledger.besu.plugin.services.query.BftQueryService;

import java.util.Collection;
import java.util.Collections;

import org.apache.tuweni.bytes.Bytes32;

public class BftQueryServiceImpl extends PoaQueryServiceImpl implements BftQueryService {

private final String consensusMechanismName;

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

@Override
public int getRoundNumberFrom(final org.hyperledger.besu.plugin.data.BlockHeader header) {
final BlockHeader headerFromChain = getHeaderFromChain(header);
final BftExtraData extraData = BftExtraData.decode(headerFromChain);
return extraData.getRound();
}

@Override
public Collection<Address> getSignersFrom(
final org.hyperledger.besu.plugin.data.BlockHeader header) {
final BlockHeader headerFromChain = getHeaderFromChain(header);
final BftExtraData extraData = BftExtraData.decode(headerFromChain);

return Collections.unmodifiableList(
BftBlockHashing.recoverCommitterAddresses(headerFromChain, extraData));
}

@Override
public String getConsensusMechanismName() {
return consensusMechanismName;
}

private BlockHeader getHeaderFromChain(
final org.hyperledger.besu.plugin.data.BlockHeader header) {
if (header instanceof BlockHeader) {
return (BlockHeader) header;
}

final Hash blockHash = Hash.wrap(Bytes32.wrap(header.getBlockHash().toArray()));
return getBlockchain().getBlockHeader(blockHash).orElseThrow();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.consensus.ibft.queries;
package org.hyperledger.besu.consensus.common.bft.queries;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
Expand All @@ -31,7 +31,7 @@
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.NonBesuBlockHeader;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.plugin.services.query.IbftQueryService;
import org.hyperledger.besu.plugin.services.query.BftQueryService;

import java.util.Collection;
import java.util.Collections;
Expand All @@ -48,7 +48,7 @@
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class IbftQueryServiceImplTest {
public class BftQueryServiceImplTest {

@Mock private Blockchain blockchain;

Expand Down Expand Up @@ -106,8 +106,8 @@ public void setup() {

@Test
public void roundNumberFromBlockIsReturned() {
final IbftQueryService service =
new IbftQueryServiceImpl(new BftBlockInterface(), blockchain, null);
final BftQueryService service =
new BftQueryServiceImpl(new BftBlockInterface(), blockchain, null, null);

assertThat(service.getRoundNumberFrom(blockHeader)).isEqualTo(ROUND_NUMBER_IN_BLOCK);
}
Expand All @@ -118,16 +118,16 @@ public void getRoundNumberThrowsIfBlockIsNotOnTheChain() {
new NonBesuBlockHeader(blockHeader.getHash(), blockHeader.getExtraData());
when(blockchain.getBlockHeader(blockHeader.getHash())).thenReturn(Optional.empty());

final IbftQueryService service =
new IbftQueryServiceImpl(new BftBlockInterface(), blockchain, null);
final BftQueryService service =
new BftQueryServiceImpl(new BftBlockInterface(), blockchain, null, null);
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> service.getRoundNumberFrom(header));
}

@Test
public void getSignersReturnsAddressesOfSignersInBlock() {
final IbftQueryService service =
new IbftQueryServiceImpl(new BftBlockInterface(), blockchain, null);
final BftQueryService service =
new BftQueryServiceImpl(new BftBlockInterface(), blockchain, null, null);

final List<Address> signers =
signingKeys.stream()
Expand All @@ -143,9 +143,16 @@ public void getSignersThrowsIfBlockIsNotOnTheChain() {
new NonBesuBlockHeader(blockHeader.getHash(), blockHeader.getExtraData());
when(blockchain.getBlockHeader(blockHeader.getHash())).thenReturn(Optional.empty());

final IbftQueryService service =
new IbftQueryServiceImpl(new BftBlockInterface(), blockchain, null);
final BftQueryService service =
new BftQueryServiceImpl(new BftBlockInterface(), blockchain, null, null);
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> service.getSignersFrom(header));
}

@Test
public void consensusMechanismNameReturnedIsSameAsThatPassedDuringCreation() {
final BftQueryService service =
new BftQueryServiceImpl(new BftBlockInterface(), blockchain, null, "consensusMechanism");
assertThat(service.getConsensusMechanismName()).isEqualTo("consensusMechanism");
}
}
2 changes: 1 addition & 1 deletion plugin-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files
knownHash = 'iPuLs9OOxBC5ZJqJ5yWrkT6LgquIDEZztdRDbSe9E3U='
knownHash = 'x0AMsmh585LzlG+avYOUH1BZOIDpQO/N9lc3X3ezcnI='
}
check.dependsOn('checkAPIChanges')

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.plugin.services.query;

import org.hyperledger.besu.plugin.data.Address;
import org.hyperledger.besu.plugin.data.BlockHeader;

import java.util.Collection;

/** Allows for the BFT specific aspects of the block chain to be queried. */
public interface BftQueryService extends PoaQueryService {

/**
* Extracts the round number from the supplied header and returns it to the caller.
*
* @param header the block header from which the round number is to be extracted
* @return The number of failed rounds executed prior to adding the block to the chain.
*/
int getRoundNumberFrom(final BlockHeader header);

/**
* Extracts the collection of signers from the supplied block header and returns them to the
* caller.
*
* @param header the block header from which a list of signers is to be extracted
* @return The addresses of
*/
Collection<Address> getSignersFrom(final BlockHeader header);

/**
* Returns the literal name of the BFT consensus mechanism is use (eg ibft or qbft), which forms
* the prefix for all BFT metrics.
*
* @return The name of the consensus mechanism being used by Besu
*/
String getConsensusMechanismName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@

import java.util.Collection;

/** Allows for the IBFT 2.0 specific aspects of the block chain to be queried. */
/**
* Allows for the IBFT 2.0 specific aspects of the block chain to be queried.
*
* @deprecated This interface has been replaced by {@link
* org.hyperledger.besu.plugin.services.query.BftQueryService}
*/
@Deprecated
public interface IbftQueryService extends PoaQueryService {

/**
Expand Down

0 comments on commit 08615f2

Please sign in to comment.