diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/IbftJsonRpcMethodsFactory.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/IbftJsonRpcMethodsFactory.java index 94c64f4fbf..dd4a91a9b5 100644 --- a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/IbftJsonRpcMethodsFactory.java +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/IbftJsonRpcMethodsFactory.java @@ -12,13 +12,16 @@ */ package tech.pegasys.pantheon.consensus.ibft.jsonrpc; +import tech.pegasys.pantheon.consensus.ibft.IbftBlockInterface; import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods.IbftDiscardValidatorVote; +import tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods.IbftGetValidatorsByBlockNumber; import tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods.IbftProposeValidatorVote; import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; import java.util.Collection; import java.util.HashMap; @@ -34,10 +37,14 @@ public class IbftJsonRpcMethodsFactory { final Map rpcMethods = new HashMap<>(); if (jsonRpcApis.contains(IbftRpcApis.IBFT)) { + BlockchainQueries blockchainQueries = + new BlockchainQueries(context.getBlockchain(), context.getWorldStateArchive()); addMethods( rpcMethods, new IbftProposeValidatorVote( context.getConsensusState().getVoteProposer(), jsonRpcParameter), + new IbftGetValidatorsByBlockNumber( + blockchainQueries, new IbftBlockInterface(), jsonRpcParameter), new IbftDiscardValidatorVote( context.getConsensusState().getVoteProposer(), jsonRpcParameter)); } diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumber.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumber.java new file mode 100644 index 0000000000..b8451eb9c0 --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumber.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019 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. + */ +package tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods; + +import tech.pegasys.pantheon.consensus.ibft.IbftBlockInterface; +import tech.pegasys.pantheon.ethereum.core.BlockHeader; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AbstractBlockParameterMethod; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.BlockParameter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; + +import java.util.Optional; + +public class IbftGetValidatorsByBlockNumber extends AbstractBlockParameterMethod + implements JsonRpcMethod { + + private final IbftBlockInterface ibftBlockInterface; + + public IbftGetValidatorsByBlockNumber( + final BlockchainQueries blockchainQueries, + final IbftBlockInterface ibftBlockInterface, + final JsonRpcParameter parameters) { + super(blockchainQueries, parameters); + this.ibftBlockInterface = ibftBlockInterface; + } + + @Override + protected BlockParameter blockParameter(final JsonRpcRequest request) { + return parameters().required(request.getParams(), 0, BlockParameter.class); + } + + @Override + protected Object resultByBlockNumber(final JsonRpcRequest request, final long blockNumber) { + final Optional blockHeader = + blockchainQueries().getBlockHeaderByNumber(blockNumber); + return blockHeader.map(header -> ibftBlockInterface.validatorsInBlock(header)).orElse(null); + } + + @Override + public String getName() { + return "ibft_getValidatorsByBlockNumber"; + } +} diff --git a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumberTest.java b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumberTest.java new file mode 100644 index 0000000000..b032b29b0a --- /dev/null +++ b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftGetValidatorsByBlockNumberTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2019 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. + */ +package tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods; + +import static org.mockito.Mockito.when; + +import tech.pegasys.pantheon.consensus.ibft.IbftBlockInterface; +import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.core.BlockHeader; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.BlockParameter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.assertj.core.api.Assertions; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class IbftGetValidatorsByBlockNumberTest { + + @Mock private BlockchainQueries blockchainQueries; + @Mock private BlockHeader blockHeader; + @Mock private IbftBlockInterface ibftBlockInterface; + @Mock private JsonRpcRequest request; + + private final JsonRpcParameter parameters = new JsonRpcParameter(); + private IbftGetValidatorsByBlockNumber method; + + @Before + public void setUp() { + method = new IbftGetValidatorsByBlockNumber(blockchainQueries, ibftBlockInterface, parameters); + } + + @Test + public void blockParameterIsParameter0() { + request = new JsonRpcRequest("?", "ignore", new String[] {"0x1245"}); + BlockParameter blockParameter = method.blockParameter(request); + Assertions.assertThat(blockParameter.getNumber().getAsLong()).isEqualTo(0x1245); + } + + @Test + public void nameShouldBeCorrect() { + Assertions.assertThat(method.getName()).isEqualTo("ibft_getValidatorsByBlockNumber"); + } + + @Test + public void shouldReturnListOfValidatorsFromBlock() { + when(blockchainQueries.getBlockHeaderByNumber(12)).thenReturn(Optional.of(blockHeader)); + final List
addresses = Collections.singletonList(Address.ID); + when(ibftBlockInterface.validatorsInBlock(blockHeader)).thenReturn(addresses); + Object result = method.resultByBlockNumber(request, 12); + Assertions.assertThat(result).isEqualTo(addresses); + } +} diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AbstractBlockParameterMethod.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AbstractBlockParameterMethod.java index 61fd9bd6df..9362b36cb1 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AbstractBlockParameterMethod.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AbstractBlockParameterMethod.java @@ -21,7 +21,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessRe import java.util.OptionalLong; -abstract class AbstractBlockParameterMethod implements JsonRpcMethod { +public abstract class AbstractBlockParameterMethod implements JsonRpcMethod { private final BlockchainQueries blockchainQueries; private final JsonRpcParameter parameters; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/queries/BlockchainQueries.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/queries/BlockchainQueries.java index eabc7639de..a06c3422d9 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/queries/BlockchainQueries.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/queries/BlockchainQueries.java @@ -370,6 +370,10 @@ public class BlockchainQueries { return blockchain.getBlockHashByNumber(blockNumber).flatMap(this::blockByHashWithTxHashes); } + public Optional getBlockHeaderByNumber(final long number) { + return blockchain.getBlockHeader(number); + } + /** * Returns the latest block with metadata and a list of transaction hashes rather than full * transactions.