diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/rlp/QbftExtraDataCLIAdapter.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/rlp/QbftExtraDataCLIAdapter.java new file mode 100644 index 0000000000..cb15ee6394 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/rlp/QbftExtraDataCLIAdapter.java @@ -0,0 +1,43 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.subcommands.rlp; + +import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; +import org.hyperledger.besu.ethereum.core.Address; + +import java.io.IOException; +import java.util.Collection; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.tuweni.bytes.Bytes; + +/** Adapter to convert a typed JSON of addresses to a QBFT RLP extra data encoding */ +public class QbftExtraDataCLIAdapter implements JSONToRLP { + private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final TypeReference> TYPE_REF = new TypeReference<>() {}; + + @Override + public Bytes encode(final String json) throws IOException { + return fromJsonAddresses(json); + } + + private Bytes fromJsonAddresses(final String jsonAddresses) throws IOException { + final Collection validatorAddresses = MAPPER.readValue(jsonAddresses, TYPE_REF); + return QbftExtraDataCodec.encodeFromAddresses( + validatorAddresses.stream().map(Address::fromHexString).collect(Collectors.toList())); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/rlp/RLPType.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/rlp/RLPType.java index 0bd6b09385..59f2e274a7 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/rlp/RLPType.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/rlp/RLPType.java @@ -17,7 +17,8 @@ package org.hyperledger.besu.cli.subcommands.rlp; /** Type of the RLP data to encode/decode */ public enum RLPType { // Enum is used to enable the listing of the possible values in PicoCLI. - IBFT_EXTRA_DATA(new IbftExtraDataCLIAdapter()); + IBFT_EXTRA_DATA(new IbftExtraDataCLIAdapter()), + QBFT_EXTRA_DATA(new QbftExtraDataCLIAdapter()); private final JSONToRLP adapter; diff --git a/besu/src/test/java/org/hyperledger/besu/cli/rlp/RLPSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/rlp/RLPSubCommandTest.java index 623f3f5834..b08c4d1c14 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/rlp/RLPSubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/rlp/RLPSubCommandTest.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.cli.CommandTestAbstract; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.IOException; import java.nio.file.Files; import org.junit.After; @@ -57,12 +58,15 @@ public class RLPSubCommandTest extends CommandTestAbstract { + System.lineSeparator() + " --type= Type of the RLP data to encode, possible values are" + System.lineSeparator() - + " IBFT_EXTRA_DATA. (default: IBFT_EXTRA_DATA)" + + " IBFT_EXTRA_DATA, QBFT_EXTRA_DATA. (default:" + + System.lineSeparator() + + " IBFT_EXTRA_DATA)" + System.lineSeparator() + " -V, --version Print version information and exit."; private static final String RLP_SUBCOMMAND_NAME = "rlp"; private static final String RLP_ENCODE_SUBCOMMAND_NAME = "encode"; + private static final String RLP_QBFT_TYPE = "QBFT_EXTRA_DATA"; // RLP sub-command @Test @@ -160,6 +164,32 @@ public class RLPSubCommandTest extends CommandTestAbstract { } } + @Test + public void canEncodeToQbftExtraData() throws IOException { + final File tempJsonFile = temp.newFile("test.json"); + try (final BufferedWriter fileWriter = Files.newBufferedWriter(tempJsonFile.toPath(), UTF_8)) { + + fileWriter.write( + "[\"be068f726a13c8d46c44be6ce9d275600e1735a4\", \"5ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193\"]"); + + fileWriter.flush(); + + parseCommand( + RLP_SUBCOMMAND_NAME, + RLP_ENCODE_SUBCOMMAND_NAME, + "--from", + tempJsonFile.getPath(), + "--type", + RLP_QBFT_TYPE); + + final String expectedRlpString = + "0xf84fa00000000000000000000000000000000000000000000000000000000000000000ea94be068f726a13c8d" + + "46c44be6ce9d275600e1735a4945ff6f4b66a46a2b2310a6f3a93aaddc0d9a1c193c080c0"; + assertThat(commandOutput.toString()).contains(expectedRlpString); + assertThat(commandErrorOutput.toString()).isEmpty(); + } + } + @Test public void encodeWithInvalidInputMustRaiseAnError() throws Exception {