Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

RLP encode subcommand #944

74 changes: 73 additions & 1 deletion docs/Reference/Pantheon-CLI-Syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -1056,4 +1056,76 @@ $ pantheon password hash --password=<my-password>

```bash tab="Example"
$ pantheon password hash --password=myPassword123
```
```

### rlp

This command provides RLP related actions.

#### encode

This command encodes a typed JSON value from a file or from the standard input into an RLP hexadecimal string.

```bash tab="Syntax"
$ pantheon rlp encode [--from=<FILE>] [--to=<FILE>] [--type=<type>]
```

```bash tab="Example using files"
$ pantheon rlp encode --from=ibft_extra_data.json --to=extra_data_for_ibft_genesis.txt --type=IBFT_EXTRA_DATA
```

```bash tab="Example using standard input/output and default type"
$ cat extra_data.json | pantheon rlp encode > rlp.txt
```

##### Available types for encoding

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 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.

??? tip "JSON Schema for IBFT_EXTRA_DATA"
The following JSON Schema can be used to validate that your JSON data is well formed.
Among many tools you can use some online validator tool like https://www.jsonschemavalidator.net/
to validate your JSON content.
```json
{
"$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"
[
"be068f726a13c8d46c44be6ce9d275600e1735a4",
"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193"
]
```
``` tab="RLP output"
0xf853a00000000000000000000000000000000000000000000000000000000000000000ea94be068f726a13c8d46c44be6ce9d275600e1735a4945ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193808400000000c0
```
1 change: 1 addition & 0 deletions pantheon/src/main/java/tech/pegasys/pantheon/Pantheon.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public static void main(final String... args) {
pantheonCommand.parse(
new RunLast().andExit(SUCCESS_EXIT_CODE),
defaultExceptionHandler().andExit(ERROR_EXIT_CODE),
System.in,
args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import picocli.CommandLine;

interface DefaultCommandValues {
public interface DefaultCommandValues {
String CONFIG_FILE_OPTION_NAME = "--config-file";

String MANDATORY_PATH_FORMAT_HELP = "<PATH>";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import tech.pegasys.pantheon.cli.custom.EnodeToURIPropertyConverter;
import tech.pegasys.pantheon.cli.custom.JsonRPCWhitelistHostsProperty;
import tech.pegasys.pantheon.cli.custom.RpcAuthFileValidator;
import tech.pegasys.pantheon.cli.rlp.RLPSubCommand;
import tech.pegasys.pantheon.config.GenesisConfigFile;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis;
import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftRpcApis;
Expand Down Expand Up @@ -58,6 +59,7 @@

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URI;
import java.nio.file.Path;
Expand Down Expand Up @@ -474,6 +476,7 @@ public PantheonCommand(
public void parse(
final AbstractParseResultHandler<List<Object>> resultHandler,
final DefaultExceptionHandler<List<Object>> exceptionHandler,
final InputStream in,
final String... args) {

commandLine = new CommandLine(this);
Expand All @@ -492,6 +495,8 @@ public void parse(
PublicKeySubCommand.COMMAND_NAME, new PublicKeySubCommand(resultHandler.out()));
commandLine.addSubcommand(
PasswordSubCommand.COMMAND_NAME, new PasswordSubCommand(resultHandler.out()));
commandLine.addSubcommand(
RLPSubCommand.COMMAND_NAME, new RLPSubCommand(resultHandler.out(), in));

commandLine.registerConverter(Address.class, Address::fromHexString);
commandLine.registerConverter(BytesValue.class, BytesValue::fromHexString);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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.cli.rlp;

import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
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.Optional;
import java.util.stream.Collectors;

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of an extra interface with an adapter, I think it would be more concise and direct to move the method body into the enum type and add an "encode" method on that enum:

shemnon@e178baf

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is that for now we only have one type in the enum but we may end up with more and I wanted to keep the enum as simple as possible by just referencing an adapter and have one adapter for each data type, well isolated into each class file. But why not. What would you think @mbaxter and @rain-on ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the same brace-initialized-enum-value pattern for future encoders, so this doesn't preclude more values in the enum.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it doesn't but the more values we'll have in the enum the more code we'll have and I'm happier with small files when possible. But I admit your proposal removes a class and an interface so why not. Waiting for a second advice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keeping the enum simple makes sense to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed I would like to try to start splitting things to prevent mega classes like PantheonCommand. CLI is usually the place where you enter Pantheon so having it very easy to navigate seems important to me. So yes it requires a bit more classes and interfaces but it also makes it easier for someone new to understand and add a feature in my opinion.


@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);

Collection<Address> addresses =
validatorAddresse.stream().map(Address::fromHexString).collect(Collectors.toList());

return new IbftExtraData(
BytesValue.wrap(new byte[32]), Collections.emptyList(), Optional.empty(), 0, addresses)
.encode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.cli.rlp;

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

import java.io.IOException;

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

/**
* Encodes the object into an RLP value.
*
* @return the RLP encoded object.
*/
BytesValue encode(String json) throws IOException;
}
Loading