Skip to content

Commit

Permalink
updated to enable specific implementation of json mapping for each type
Browse files Browse the repository at this point in the history
update doc accordingly
  • Loading branch information
NicolasMassart committed Feb 25, 2019
1 parent 9439640 commit be17af4
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 101 deletions.
59 changes: 22 additions & 37 deletions docs/Reference/Pantheon-CLI-Syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -1084,8 +1084,8 @@ For the moment, only IBFT extra data type of RLP data is supported.
This data is used to build the IBFT 2.0 genesis file.

???+ summary "IBFT_EXTRA_DATA"
To generate the IBFT_EXTRA_DATA typed RLP string you need a JSON input containing all the validator
addresses that you want to insert in your genesis.
To generate the IBFT_EXTRA_DATA typed RLP string you need a JSON input containing an array with
all the validator addresses strings that you want to insert in your genesis.

The JSON content is an object with a validator property that's an array of validator addresse strings.

Expand All @@ -1097,48 +1097,33 @@ This data is used to build the IBFT 2.0 genesis file.
```json
{
"$schema":"",
"$id":"http://tech.pegasys.pantheon/cli_rlp_ibft_extra_data.json",
"type":"object",
"title":"IBFT extra data",
"description":"JSON format used as input to generate an IBFT extra data RLP string",
"default":null,
"definitions":{
},
"required":[
"validators"
],
"properties":{
"validators":{
"$id":"#/properties/validators",
"type":"array",
"title":"Validators addresses list",
"description":"List of validator addresses to use in the extra data",
"default":null,
"items":{
"$id":"#/properties/validators/items",
"type":"string",
"title":"Validator address",
"description":"The validator node address",
"default":"",
"examples":[
"be068f726a13c8d46c44be6ce9d275600e1735a4",
"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193"
],
"pattern":"^([0-9a-f]{40})$"
}
}
}
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://tech.pegasys.pantheon/cli_rlp_ibft_extra_data.json",
"type": "array",
"definitions": {},
"title": "IBFT extra data",
"description":"JSON format used as input to generate an IBFT extra data RLP string",
"items": {
"$id": "#/address",
"type": "string",
"title": "Validator address",
"description":"The validator node address",
"default": "",
"examples": [
"be068f726a13c8d46c44be6ce9d275600e1735a4",
"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193"
],
"pattern":"^([0-9a-f]{40})$"
}
}
```
!!!example "Example IBFT_EXTRA_DATA encoding"
```json tab="JSON input"
{"validators":[
[
"be068f726a13c8d46c44be6ce9d275600e1735a4",
"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193"
]}
]
```
``` tab="RLP output"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,32 @@
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
* Adapter to convert a typed JSON to an IbftExtraData object This adapter handles the JSON to RLP
* encoding
*/
public class IbftExtraDataCLIAdapter implements JSONToRLP {

private final List<Address> validators;
@Override
public BytesValue encode(final String json) throws IOException {
ObjectMapper mapper = new ObjectMapper();
TypeReference<Collection<String>> typeRef = new TypeReference<Collection<String>>() {};
Collection<String> validatorAddresse = mapper.readValue(json, typeRef);

@JsonCreator
IbftExtraDataCLIAdapter(@JsonProperty("validators") final Collection<String> validators) {
this.validators = validators.stream().map(Address::fromHexString).collect(Collectors.toList());
}
Collection<Address> addresses =
validatorAddresse.stream().map(Address::fromHexString).collect(Collectors.toList());

@Override
public BytesValue encode() {
return new IbftExtraData(
BytesValue.wrap(new byte[32]), Collections.emptyList(), Optional.empty(), 0, validators)
BytesValue.wrap(new byte[32]), Collections.emptyList(), Optional.empty(), 0, addresses)
.encode();
}

@Override
public Class<? extends JSONToRLP> getType() {
return this.getClass();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.io.IOException;

/** Behaviour of objects that can be encoded from JSON to RLP */
interface JSONToRLP {

Expand All @@ -22,12 +24,5 @@ interface JSONToRLP {
*
* @return the RLP encoded object.
*/
BytesValue encode();

/**
* Gives the type of the object that's being encoded
*
* @return the type of the current object that must be a type implementing this interface
*/
Class<? extends JSONToRLP> getType();
BytesValue encode(String json) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
import java.nio.file.Path;
import java.util.Scanner;

import io.vertx.core.json.DecodeException;
import io.vertx.core.json.JsonObject;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import picocli.CommandLine.Command;
Expand Down Expand Up @@ -157,27 +156,22 @@ private void readInput() {
* @param jsonInput the JSON string data to encode
*/
private void encode(final String jsonInput) {
// map the json to the object matching the type option
// the object must be a JSONToRLP object
if (jsonInput == null || jsonInput.isEmpty()) {
throw new ParameterException(
spec.commandLine(), "An error occurred while trying to read the JSON data.");
} else {
try {
JsonObject jsonObject = new JsonObject(jsonInput);
JSONToRLP objectToEncode = jsonObject.mapTo(type.getType());

// encode and write the value
writeOutput(objectToEncode.encode());
} catch (DecodeException e) {
writeOutput(type.getAdapter().encode(jsonInput));
} catch (MismatchedInputException e) {
throw new ParameterException(
spec.commandLine(),
"Unable to load the JSON data. Please check JSON input format. " + e.getMessage());
} catch (IllegalArgumentException e) {
"Unable to map the JSON data with selected type. Please check JSON input format. "
+ e);
} catch (IOException e) {
throw new ParameterException(
spec.commandLine(),
"Unable to map the JSON data with IbftExtraData type. Please check JSON input format. "
+ e.getMessage());
"Unable to load the JSON data. Please check JSON input format. " + e);
}
}
}
Expand Down
23 changes: 12 additions & 11 deletions pantheon/src/main/java/tech/pegasys/pantheon/cli/rlp/RLPType.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@
package tech.pegasys.pantheon.cli.rlp;

/** Type of the RLP data to encode/decode */
public enum RLPType implements RLPTypeProvider {
public enum RLPType {
// Enum is used to enable the listing of the possible values in PicoCLI.
IBFT_EXTRA_DATA {
@Override
public Class<? extends JSONToRLP> getType() {
return IbftExtraDataCLIAdapter.class;
}
};
}
IBFT_EXTRA_DATA(new IbftExtraDataCLIAdapter());

private final JSONToRLP adapter;

RLPType(final JSONToRLP adapter) {

this.adapter = adapter;
}

/** Enables the behaviour of being a type provider on the enum value */
interface RLPTypeProvider {
Class<? extends JSONToRLP> getType();
public JSONToRLP getAdapter() {
return adapter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,10 @@ public void callingRPLEncodeSubCommandHelpMustDisplayUsage() {
}

@Test
public void callingRLPEncodeSubCommandWithoutPathMustWriteToStandardOutput() {
public void encodeWithoutPathMustWriteToStandardOutput() {

final String jsonInput =
"{\"validators\":[\"be068f726a13c8d46c44be6ce9d275600e1735a4\",\n"
+ "\"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193\" ]}";
"[\"be068f726a13c8d46c44be6ce9d275600e1735a4\", \"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193\"]";

// set stdin
final ByteArrayInputStream stdIn = new ByteArrayInputStream(jsonInput.getBytes(UTF_8));
Expand All @@ -115,13 +114,12 @@ public void callingRLPEncodeSubCommandWithoutPathMustWriteToStandardOutput() {
}

@Test
public void callingRLPEncodeSubCommandWithOutputFileMustWriteInThisFile() throws Exception {
public void encodeWithOutputFileMustWriteInThisFile() throws Exception {

final File file = File.createTempFile("ibftExtraData", "rlp");

final String jsonInput =
"{\"validators\":[\"be068f726a13c8d46c44be6ce9d275600e1735a4\",\n"
+ "\"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193\" ]}";
"[\"be068f726a13c8d46c44be6ce9d275600e1735a4\", \"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193\"]";

// set stdin
final ByteArrayInputStream stdIn = new ByteArrayInputStream(jsonInput.getBytes(UTF_8));
Expand All @@ -139,16 +137,13 @@ public void callingRLPEncodeSubCommandWithOutputFileMustWriteInThisFile() throws
}

@Test
public void callingRLPEncodeSubCommandWithInputFilePathMustReadFromThisFile() throws Exception {
public void encodeWithInputFilePathMustReadFromThisFile() throws Exception {

final File tempJsonFile = temp.newFile("test.json");
try (final BufferedWriter fileWriter = Files.newBufferedWriter(tempJsonFile.toPath(), UTF_8)) {

fileWriter.write(
"{\"validators\":[\n"
+ " \"be068f726a13c8d46c44be6ce9d275600e1735a4\",\n"
+ " \"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193\"\n"
+ "]}");
"[\"be068f726a13c8d46c44be6ce9d275600e1735a4\", \"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193\"]");

fileWriter.flush();

Expand All @@ -164,12 +159,12 @@ public void callingRLPEncodeSubCommandWithInputFilePathMustReadFromThisFile() th
}

@Test
public void callingRLPEncodeSubCommandWithInvalidInputMustRaiseAnError() throws Exception {
public void encodeWithInvalidInputMustRaiseAnError() throws Exception {

final File tempJsonFile = temp.newFile("invalid_test.json");
try (final BufferedWriter fileWriter = Files.newBufferedWriter(tempJsonFile.toPath(), UTF_8)) {

fileWriter.write("{\"validators\":0}");
fileWriter.write("{\"property\":0}");

fileWriter.flush();

Expand All @@ -179,12 +174,12 @@ public void callingRLPEncodeSubCommandWithInvalidInputMustRaiseAnError() throws
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString())
.startsWith(
"Unable to map the JSON data with IbftExtraData type. Please check JSON input format.");
"Unable to map the JSON data with selected type. Please check JSON input format.");
}
}

@Test
public void callingRLPEncodeSubCommandWithEmptyInputMustRaiseAnError() throws Exception {
public void encodeWithEmptyInputMustRaiseAnError() throws Exception {

final File tempJsonFile = temp.newFile("empty.json");

Expand All @@ -196,7 +191,7 @@ public void callingRLPEncodeSubCommandWithEmptyInputMustRaiseAnError() throws Ex
}

@Test
public void callingRLPEncodeSubCommandWithEmptyStdInputMustRaiseAnError() throws Exception {
public void encodeWithEmptyStdInputMustRaiseAnError() throws Exception {

// set empty stdin
final String jsonInput = "";
Expand Down

0 comments on commit be17af4

Please sign in to comment.