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 dd3225e57d..285aaf6da0 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 @@ -1,6 +1,7 @@ package tech.pegasys.pantheon.consensus.ibft.jsonrpc; import tech.pegasys.pantheon.consensus.ibft.IbftContext; +import tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods.IbftDiscardValidatorVote; import tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods.IbftProposeValidatorVote; import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; @@ -20,6 +21,8 @@ public class IbftJsonRpcMethodsFactory { addMethods( rpcMethods, new IbftProposeValidatorVote( + context.getConsensusState().getVoteProposer(), jsonRpcParameter), + new IbftDiscardValidatorVote( context.getConsensusState().getVoteProposer(), jsonRpcParameter)); return rpcMethods; diff --git a/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftDiscardValidatorVote.java b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftDiscardValidatorVote.java new file mode 100644 index 0000000000..48bbc6e48f --- /dev/null +++ b/consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftDiscardValidatorVote.java @@ -0,0 +1,35 @@ +package tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods; + +import tech.pegasys.pantheon.consensus.common.VoteProposer; +import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +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.response.JsonRpcResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; + +public class IbftDiscardValidatorVote implements JsonRpcMethod { + private final VoteProposer voteProposer; + private final JsonRpcParameter parameters; + + public IbftDiscardValidatorVote( + final VoteProposer voteProposer, final JsonRpcParameter parameters) { + this.voteProposer = voteProposer; + this.parameters = parameters; + } + + @Override + public String getName() { + return "ibft_discardValidatorVote"; + } + + @Override + public JsonRpcResponse response(final JsonRpcRequest req) { + + final Address validatorAddress = parameters.required(req.getParams(), 0, Address.class); + + voteProposer.discard(validatorAddress); + + return new JsonRpcSuccessResponse(req.getId(), true); + } +} diff --git a/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftDiscardValidatorVoteTest.java b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftDiscardValidatorVoteTest.java new file mode 100644 index 0000000000..f0f82880f7 --- /dev/null +++ b/consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/jsonrpc/methods/IbftDiscardValidatorVoteTest.java @@ -0,0 +1,76 @@ +package tech.pegasys.pantheon.consensus.ibft.jsonrpc.methods; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import tech.pegasys.pantheon.consensus.common.VoteProposer; +import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.exception.InvalidJsonRpcParameters; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class IbftDiscardValidatorVoteTest { + private final VoteProposer voteProposer = mock(VoteProposer.class); + private final JsonRpcParameter jsonRpcParameter = new JsonRpcParameter(); + private final String IBFT_METHOD = "ibft_discardValidatorVote"; + private final String JSON_RPC_VERSION = "2.0"; + private IbftDiscardValidatorVote method; + + @Rule public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setup() { + method = new IbftDiscardValidatorVote(voteProposer, jsonRpcParameter); + } + + @Test + public void returnsCorrectMethodName() { + assertThat(method.getName()).isEqualTo(IBFT_METHOD); + } + + @Test + public void exceptionWhenNoParamsSupplied() { + final JsonRpcRequest request = requestWithParams(); + + expectedException.expect(InvalidJsonRpcParameters.class); + expectedException.expectMessage("Missing required json rpc parameter at index 0"); + + method.response(request); + } + + @Test + public void exceptionWhenInvalidAddressParameterSupplied() { + final JsonRpcRequest request = requestWithParams("InvalidAddress"); + + expectedException.expect(InvalidJsonRpcParameters.class); + expectedException.expectMessage("Invalid json rpc parameter at index 0"); + + method.response(request); + } + + @Test + public void discardValidator() { + final Address parameterAddress = Address.fromHexString("1"); + final JsonRpcRequest request = requestWithParams(parameterAddress); + + JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(request.getId(), true); + + JsonRpcResponse response = method.response(request); + + assertThat(response).isEqualToComparingFieldByField(expectedResponse); + + verify(voteProposer).discard(parameterAddress); + } + + private JsonRpcRequest requestWithParams(final Object... params) { + return new JsonRpcRequest(JSON_RPC_VERSION, IBFT_METHOD, params); + } +}