diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueExtraData.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueExtraData.java index bd18a99fdb..dcd59b6af9 100644 --- a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueExtraData.java +++ b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueExtraData.java @@ -15,8 +15,11 @@ package tech.pegasys.pantheon.consensus.clique; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import tech.pegasys.pantheon.crypto.SECP256K1.PrivateKey; +import tech.pegasys.pantheon.crypto.SECP256K1.PublicKey; import tech.pegasys.pantheon.crypto.SECP256K1.Signature; import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValues; @@ -106,4 +109,21 @@ public class CliqueExtraData { public List
getValidators() { return validators; } + + public static String createGenesisExtraDataString(final List privKeys) { + final List
validators = convertPrivKeysToAddresses(privKeys); + final CliqueExtraData cliqueExtraData = + new CliqueExtraData(BytesValue.wrap(new byte[32]), null, validators); + final BytesValue output = cliqueExtraData.encode(); + return output.toString(); + } + + private static List
convertPrivKeysToAddresses(final List privKeys) { + final List
validators = Lists.newArrayList(); + for (PrivateKey privKey : privKeys) { + final PublicKey pubKey = PublicKey.create(privKey); + validators.add(Util.publicKeyToAddress(pubKey)); + } + return validators; + } } diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueExtraDataTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueExtraDataTest.java index 904b327b3a..8d17892b8a 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueExtraDataTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueExtraDataTest.java @@ -15,15 +15,20 @@ package tech.pegasys.pantheon.consensus.clique; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; +import tech.pegasys.pantheon.crypto.SECP256K1.PrivateKey; import tech.pegasys.pantheon.crypto.SECP256K1.Signature; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.AddressHelpers; +import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.math.BigInteger; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; +import com.google.common.collect.Lists; import org.bouncycastle.util.encoders.Hex; import org.junit.Test; @@ -88,4 +93,28 @@ public class CliqueExtraDataTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("BytesValue is of invalid size - i.e. contains unused bytes."); } + + @Test + public void privKeysToExtraDataString() { + List nodeKeys = Lists.newArrayList(); + for (int i = 0; i < 4; i++) { + nodeKeys.add(KeyPair.generate()); + } + + final List privKeys = + nodeKeys.stream().map(k -> k.getPrivateKey()).collect(Collectors.toList()); + + final String hexOutput = CliqueExtraData.createGenesisExtraDataString(privKeys); + + final CliqueExtraData extraData = CliqueExtraData.decode(BytesValue.fromHexString(hexOutput)); + + final List
expectedAddresses = + nodeKeys + .stream() + .map(k -> Util.publicKeyToAddress(k.getPublicKey())) + .collect(Collectors.toList()); + + assertThat(extraData.getValidators()) + .containsExactly(expectedAddresses.toArray(new Address[expectedAddresses.size()])); + } }