From f4b9b563549f9451d86c81c7faaf1076f6d87861 Mon Sep 17 00:00:00 2001 From: Roberto Saltini <38655434+saltiniroberto@users.noreply.github.com> Date: Tue, 23 Oct 2018 13:13:54 +1100 Subject: [PATCH] [NC-1778] Added Clique JSON RPC method clique_proposals (#123) --- .../jsonrpc/CliqueJsonRpcMethodsFactory.java | 3 + .../jsonrpc/methods/CliqueProposals.java | 52 +++++++++++++ .../jsonrpc/methods/CliqueProposalsTest.java | 73 +++++++++++++++++++ .../consensus/common/VoteProposer.java | 4 + 4 files changed, 132 insertions(+) create mode 100644 consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueProposals.java create mode 100644 consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueProposalsTest.java diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/CliqueJsonRpcMethodsFactory.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/CliqueJsonRpcMethodsFactory.java index 86d7c0eecc..e1967cde00 100644 --- a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/CliqueJsonRpcMethodsFactory.java +++ b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/CliqueJsonRpcMethodsFactory.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.consensus.clique.CliqueVoteTallyUpdater; import tech.pegasys.pantheon.consensus.clique.VoteTallyCache; import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueGetSigners; import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueGetSignersAtHash; +import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.CliqueProposals; import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.Discard; import tech.pegasys.pantheon.consensus.clique.jsonrpc.methods.Propose; import tech.pegasys.pantheon.consensus.common.EpochManager; @@ -56,11 +57,13 @@ public class CliqueJsonRpcMethodsFactory { new CliqueGetSignersAtHash(blockchainQueries, voteTallyCache, jsonRpcParameter); final Propose proposeRpc = new Propose(voteProposer, jsonRpcParameter); final Discard discardRpc = new Discard(voteProposer, jsonRpcParameter); + final CliqueProposals cliqueProposals = new CliqueProposals(voteProposer); rpcMethods.put(cliqueGetSigners.getName(), cliqueGetSigners); rpcMethods.put(cliqueGetSignersAtHash.getName(), cliqueGetSignersAtHash); rpcMethods.put(proposeRpc.getName(), proposeRpc); rpcMethods.put(discardRpc.getName(), discardRpc); + rpcMethods.put(cliqueProposals.getName(), cliqueProposals); return rpcMethods; } diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueProposals.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueProposals.java new file mode 100644 index 0000000000..6b25f342ce --- /dev/null +++ b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueProposals.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 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.clique.jsonrpc.methods; + +import tech.pegasys.pantheon.consensus.common.VoteProposer; +import tech.pegasys.pantheon.consensus.common.VoteType; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; + +import java.util.Map; +import java.util.stream.Collectors; + +public class CliqueProposals implements JsonRpcMethod { + public static final String CLIQUE_PROPOSALS = "clique_proposals"; + private final VoteProposer voteProposer; + + public CliqueProposals(final VoteProposer voteProposer) { + this.voteProposer = voteProposer; + } + + @Override + public String getName() { + return CLIQUE_PROPOSALS; + } + + @Override + public JsonRpcResponse response(final JsonRpcRequest request) { + Map proposals = + voteProposer + .getProposals() + .entrySet() + .stream() + .collect( + Collectors.toMap( + proposal -> proposal.getKey().toString(), + proposal -> proposal.getValue() == VoteType.ADD)); + + return new JsonRpcSuccessResponse(request.getId(), proposals); + } +} diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueProposalsTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueProposalsTest.java new file mode 100644 index 0000000000..96215e6f27 --- /dev/null +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/jsonrpc/methods/CliqueProposalsTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 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.clique.jsonrpc.methods; + +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import tech.pegasys.pantheon.consensus.common.VoteProposer; +import tech.pegasys.pantheon.consensus.common.VoteType; +import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; + +import com.google.common.collect.ImmutableMap; +import org.junit.Before; +import org.junit.Test; + +public class CliqueProposalsTest { + + private final VoteProposer voteProposer = mock(VoteProposer.class); + private final String METHOD_NAME = "clique_proposals"; + private final String JSON_RPC_VERSION = "2.0"; + private CliqueProposals method; + + @Before + public void setup() { + method = new CliqueProposals(voteProposer); + } + + @Test + public void returnsCorrectMethodName() { + assertThat(method.getName()).isEqualTo(METHOD_NAME); + } + + @Test + public void testConversionFromVoteTypeToBoolean() { + final JsonRpcRequest request = + new JsonRpcRequest(JSON_RPC_VERSION, METHOD_NAME, new Object[] {}); + + when(voteProposer.getProposals()) + .thenReturn( + ImmutableMap.of( + Address.fromHexString("1"), + VoteType.ADD, + Address.fromHexString("2"), + VoteType.DROP)); + + JsonRpcResponse expectedResponse = + new JsonRpcSuccessResponse( + request.getId(), + ImmutableMap.of( + "0x0000000000000000000000000000000000000001", + true, + "0x0000000000000000000000000000000000000002", + false)); + + JsonRpcResponse response = method.response(request); + + assertThat(response).isEqualToComparingFieldByField(expectedResponse); + } +} diff --git a/consensus/common/src/main/java/tech/pegasys/pantheon/consensus/common/VoteProposer.java b/consensus/common/src/main/java/tech/pegasys/pantheon/consensus/common/VoteProposer.java index 63fdeafe8e..4993688225 100644 --- a/consensus/common/src/main/java/tech/pegasys/pantheon/consensus/common/VoteProposer.java +++ b/consensus/common/src/main/java/tech/pegasys/pantheon/consensus/common/VoteProposer.java @@ -60,6 +60,10 @@ public class VoteProposer { proposals.clear(); } + public Map getProposals() { + return proposals; + } + public Optional get(final Address address) { return Optional.ofNullable(proposals.get(address)); }