Skip to content

Commit

Permalink
add rlp decode subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
Brindrajsinh-Chauhan committed Apr 6, 2024
1 parent c589c5b commit 88e4b60
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.cli.subcommands.rlp;

import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.ibft.IbftExtraDataCodec;
import org.hyperledger.besu.datatypes.Address;

Expand Down Expand Up @@ -43,4 +44,13 @@ private Bytes fromJsonAddresses(final String jsonAddresses) throws IOException {
return IbftExtraDataCodec.encodeFromAddresses(
validatorAddresses.stream().map(Address::fromHexString).collect(Collectors.toList()));
}

@Override
public BftExtraData decode(final String rlpInput) throws IOException {
return fromRLPInput(rlpInput);
}

private BftExtraData fromRLPInput(final String rlpInput) throws IOException {
return new IbftExtraDataCodec().decodeRaw(Bytes.fromHexString(rlpInput));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.cli.subcommands.rlp;

import org.hyperledger.besu.consensus.common.bft.BftExtraData;

import java.io.IOException;

import org.apache.tuweni.bytes.Bytes;
Expand All @@ -29,4 +31,13 @@ interface JSONToRLP {
* @throws IOException if an error occurs while reading data
*/
Bytes encode(String json) throws IOException;

/**
* Decodes the input RLP value into a validators list Object.
*
* @param inputData the RLP hex string to convert to validators list
* @return the decoded BFT ExtraData object.
* @throws IOException if an error occurs while reading data
*/
BftExtraData decode(String inputData) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.cli.subcommands.rlp;

import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec;
import org.hyperledger.besu.datatypes.Address;

Expand All @@ -40,4 +41,13 @@ private Bytes fromJsonAddresses(final String jsonAddresses) throws IOException {
return QbftExtraDataCodec.encodeFromAddresses(
validatorAddresses.stream().map(Address::fromHexString).collect(Collectors.toList()));
}

@Override
public BftExtraData decode(final String rlpInput) throws IOException {
return fromRLPInput(rlpInput);
}

private BftExtraData fromRLPInput(final String rlpInput) throws IOException {
return new QbftExtraDataCodec().decodeRaw(Bytes.fromHexString(rlpInput));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@

import org.hyperledger.besu.cli.BesuCommand;
import org.hyperledger.besu.cli.DefaultCommandValues;
import org.hyperledger.besu.cli.subcommands.rlp.RLPSubCommand.DecodeSubCommand;
import org.hyperledger.besu.cli.subcommands.rlp.RLPSubCommand.EncodeSubCommand;
import org.hyperledger.besu.cli.util.VersionProvider;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;

import java.io.BufferedReader;
import java.io.BufferedWriter;
Expand Down Expand Up @@ -48,7 +50,7 @@
description = "This command provides RLP data related actions.",
mixinStandardHelpOptions = true,
versionProvider = VersionProvider.class,
subcommands = {EncodeSubCommand.class})
subcommands = {EncodeSubCommand.class, DecodeSubCommand.class})
public class RLPSubCommand implements Runnable {

/** The constant COMMAND_NAME. */
Expand Down Expand Up @@ -207,4 +209,126 @@ private void writeOutput(final Bytes rlpEncodedOutput) {
}
}
}

/**
* RLP decode sub-command
*
* <p>Decode a RLP hex string into a validator list.
*/
@Command(
name = "decode",
description = "This command decodes a JSON typed RLP hex string into validator list.",
mixinStandardHelpOptions = true,
versionProvider = VersionProvider.class)
static class DecodeSubCommand implements Runnable {

@SuppressWarnings("unused")
@ParentCommand
private RLPSubCommand parentCommand; // Picocli injects reference to parent command

@SuppressWarnings("unused")
@Spec
private CommandSpec spec;

@Option(
names = "--type",
description =
"Type of the RLP data to Decode, possible values are ${COMPLETION-CANDIDATES}. (default: ${DEFAULT-VALUE})",
arity = "1..1")
private final RLPType type = RLPType.IBFT_EXTRA_DATA;

@Option(
names = "--from",
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP,
description = "File containing JSON object to decode",
arity = "1..1")
private final File jsonSourceFile = null;

@Option(
names = "--to",
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP,
description = "File to write decoded RLP string to.",
arity = "1..1")
private final File rlpTargetFile = null;

@Override
public void run() {
checkNotNull(parentCommand);
readInput();
}

/**
* Reads the stdin or from a file if one is specified by {@link #jsonSourceFile} then goes to
* {@link #decode(String)} this data
*/
private void readInput() {
// if we have an output file defined, print to it
// otherwise print to defined output, usually standard output.
final String inputData;

if (jsonSourceFile != null) {
try {
BufferedReader reader = Files.newBufferedReader(jsonSourceFile.toPath(), UTF_8);

// Read only the first line if there are many lines
inputData = reader.readLine();
} catch (IOException e) {
throw new ExecutionException(spec.commandLine(), "Unable to read JSON file.");
}
} else {
// get data from standard input
try (Scanner scanner = new Scanner(parentCommand.in, UTF_8.name())) {
inputData = scanner.nextLine();
}
}

decode(inputData);
}

/**
* Decodes the string input into an validator data based on the {@link #type} then goes to
* {@link #writeOutput(BftExtraData)} this data to file or stdout
*
* @param inputData the string data to decode
*/
private void decode(final String inputData) {
if (inputData == null || inputData.isEmpty()) {
throw new ParameterException(
spec.commandLine(), "An error occurred while trying to read the input data.");
} else {
try {
// decode and write the value
writeOutput(type.getAdapter().decode(inputData));
} catch (MismatchedInputException e) {
throw new ParameterException(
spec.commandLine(),
"Unable to map the input data with selected type. Please check input format. " + e);
} catch (IOException e) {
throw new ParameterException(
spec.commandLine(), "Unable to load the input data. Please check input format. " + e);
}
}
}

/**
* write the decoded result to stdout or a file if the option is specified
*
* @param bftExtraDataOutput the BFT extra data output to write to file or stdout
*/
private void writeOutput(final BftExtraData bftExtraDataOutput) {
if (rlpTargetFile != null) {
final Path targetPath = rlpTargetFile.toPath();

try (final BufferedWriter fileWriter = Files.newBufferedWriter(targetPath, UTF_8)) {
fileWriter.write(bftExtraDataOutput.getValidators().toString());
} catch (final IOException e) {
throw new ParameterException(
spec.commandLine(),
"An error occurred while trying to write the validator list. " + e.getMessage());
}
} else {
parentCommand.out.println(bftExtraDataOutput.getValidators().toString());
}
}
}
}

0 comments on commit 88e4b60

Please sign in to comment.