[NC-1582] Added ExtraData for iBFT 2.0 (#37)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Roberto Saltini 6 years ago committed by GitHub
parent bc05f38a03
commit 4644fe0080
  1. 121
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/Ibft2ExtraData.java
  2. 47
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/Ibft2VoteType.java
  3. 87
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/Vote.java
  4. 415
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/Ibft2ExtraDataTest.java
  5. 30
      consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/VoteTest.java

@ -0,0 +1,121 @@
/*
* Copyright 2018 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.consensus.ibft;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPInput;
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.List;
import java.util.Optional;
/**
* Represents the data structure stored in the extraData field of the BlockHeader used when
* operating under an IBFT 2.0 consensus mechanism.
*/
public class Ibft2ExtraData {
public static final int EXTRA_VANITY_LENGTH = 32;
private final BytesValue vanityData;
private final List<Signature> seals;
private final Optional<Vote> vote;
private final int round;
private final List<Address> validators;
public Ibft2ExtraData(
final BytesValue vanityData,
final List<Signature> seals,
final Optional<Vote> vote,
final int round,
final List<Address> validators) {
checkNotNull(vanityData);
checkNotNull(seals);
checkNotNull(validators);
this.vanityData = vanityData;
this.seals = seals;
this.round = round;
this.validators = validators;
this.vote = vote;
}
public static Ibft2ExtraData decode(final BytesValue input) {
checkArgument(
input.size() > EXTRA_VANITY_LENGTH,
"Invalid BytesValue supplied - too short to produce a valid IBFT Extra Data object.");
final RLPInput rlpInput = new BytesValueRLPInput(input, false);
rlpInput.enterList(); // This accounts for the "root node" which contains IBFT data items.
final BytesValue vanityData = rlpInput.readBytesValue();
final List<Address> validators = rlpInput.readList(Address::readFrom);
final Optional<Vote> vote;
if (rlpInput.nextIsNull()) {
vote = Optional.empty();
rlpInput.skipNext();
} else {
vote = Optional.of(Vote.readFrom(rlpInput));
}
final int round = rlpInput.readInt();
final List<Signature> seals = rlpInput.readList(rlp -> Signature.decode(rlp.readBytesValue()));
rlpInput.leaveList();
return new Ibft2ExtraData(vanityData, seals, vote, round, validators);
}
public BytesValue encode() {
final BytesValueRLPOutput encoder = new BytesValueRLPOutput();
encoder.startList();
encoder.writeBytesValue(vanityData);
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator));
if (vote.isPresent()) {
vote.get().writeTo(encoder);
} else {
encoder.writeNull();
}
encoder.writeInt(round);
encoder.writeList(seals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes()));
encoder.endList();
return encoder.encoded();
}
// Accessors
public BytesValue getVanityData() {
return vanityData;
}
public List<Signature> getSeals() {
return seals;
}
public List<Address> getValidators() {
return validators;
}
public Optional<Vote> getVote() {
return vote;
}
public int getRound() {
return round;
}
}

@ -0,0 +1,47 @@
/*
* Copyright 2018 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.consensus.ibft;
import tech.pegasys.pantheon.ethereum.rlp.RLPException;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
public enum Ibft2VoteType {
ADD((byte) 0xFF),
DROP((byte) 0x00);
private final byte voteValue;
Ibft2VoteType(final byte voteValue) {
this.voteValue = voteValue;
}
public byte getVoteValue() {
return voteValue;
}
public static Ibft2VoteType readFrom(final RLPInput rlpInput) {
byte encodedByteValue = rlpInput.readByte();
for (final Ibft2VoteType voteType : values()) {
if (voteType.voteValue == encodedByteValue) {
return voteType;
}
}
throw new RLPException("Invalid Ibft2VoteType RLP encoding");
}
public void writeTo(final RLPOutput rlpOutput) {
rlpOutput.writeByte(voteValue);
}
}

@ -0,0 +1,87 @@
/*
* Copyright 2018 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.consensus.ibft;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLPOutput;
import com.google.common.base.Objects;
public class Vote {
private final Address recipient;
private final Ibft2VoteType voteType;
private Vote(final Address recipient, final Ibft2VoteType voteType) {
this.recipient = recipient;
this.voteType = voteType;
}
public static Vote authVote(final Address address) {
return new Vote(address, Ibft2VoteType.ADD);
}
public static Vote dropVote(final Address address) {
return new Vote(address, Ibft2VoteType.DROP);
}
public Address getRecipient() {
return recipient;
}
public boolean isAuth() {
return voteType.equals(Ibft2VoteType.ADD);
}
public boolean isDrop() {
return voteType.equals(Ibft2VoteType.DROP);
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Vote vote1 = (Vote) o;
return recipient.equals(vote1.recipient) && voteType.equals(vote1.voteType);
}
@Override
public int hashCode() {
return Objects.hashCode(recipient, voteType);
}
public Ibft2VoteType getVoteType() {
return voteType;
}
public void writeTo(final RLPOutput rlpOutput) {
rlpOutput.startList();
rlpOutput.writeBytesValue(recipient);
voteType.writeTo(rlpOutput);
rlpOutput.endList();
}
public static Vote readFrom(final RLPInput rlpInput) {
rlpInput.enterList();
final Address recipient = Address.readFrom(rlpInput);
final Ibft2VoteType vote = Ibft2VoteType.readFrom(rlpInput);
rlpInput.leaveList();
return new Vote(recipient, vote);
}
}

@ -0,0 +1,415 @@
/*
* Copyright 2018 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.consensus.ibft;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import tech.pegasys.pantheon.crypto.SECP256K1.Signature;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput;
import tech.pegasys.pantheon.ethereum.rlp.RLPException;
import tech.pegasys.pantheon.ethereum.rlp.RLPInput;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import com.google.common.collect.Lists;
import org.junit.Test;
public class Ibft2ExtraDataTest {
private final String RAW_HEX_ENCODING_STRING =
"f8f1a00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20ea9400000000000000000000000000000000000"
+ "00001940000000000000000000000000000000000000002d794000000000000000000000000000000000000000181ff8400fedc"
+ "baf886b841000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000"
+ "0000000000000000000000000000000000a00b84100000000000000000000000000000000000000000000000000000000000000"
+ "0a000000000000000000000000000000000000000000000000000000000000000100";
private final Ibft2ExtraData DECODED_EXTRA_DATA_FOR_RAW_HEX_ENCODING_STRING =
getDecodedExtraDataForRawHexEncodingString();
private static Ibft2ExtraData getDecodedExtraDataForRawHexEncodingString() {
final List<Address> validators =
Arrays.asList(Address.fromHexString("1"), Address.fromHexString("2"));
final Optional<Vote> vote = Optional.of(Vote.authVote(Address.fromHexString("1")));
final int round = 0x00FEDCBA;
final List<Signature> committerSeals =
Arrays.asList(
Signature.create(BigInteger.ONE, BigInteger.TEN, (byte) 0),
Signature.create(BigInteger.TEN, BigInteger.ONE, (byte) 0));
// Create a byte buffer with no data.
final byte[] vanity_bytes = createNonEmptyVanityData();
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
return new Ibft2ExtraData(vanity_data, committerSeals, vote, round, validators);
}
@Test
public void correctlyCodedRoundConstitutesValidContent() {
final List<Address> validators = Lists.newArrayList();
final Optional<Vote> vote = Optional.of(Vote.authVote(Address.fromHexString("1")));
final int round = 0x00FEDCBA;
final byte[] roundAsByteArray = new byte[] {(byte) 0x00, (byte) 0xFE, (byte) 0xDC, (byte) 0xBA};
final List<Signature> committerSeals = Lists.newArrayList();
// Create a byte buffer with no data.
final byte[] vanity_bytes = new byte[32];
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
final BytesValueRLPOutput encoder = new BytesValueRLPOutput();
encoder.startList();
encoder.writeBytesValue(vanity_data);
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator));
// encoded vote
encoder.startList();
encoder.writeBytesValue(vote.get().getRecipient());
vote.get().getVoteType().writeTo(encoder);
encoder.endList();
// This is to verify that the decoding works correctly when the round is encoded as 4 bytes
encoder.writeBytesValue(BytesValue.wrap(roundAsByteArray));
encoder.writeList(
committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes()));
encoder.endList();
final BytesValue bufferToInject = encoder.encoded();
final Ibft2ExtraData extraData = Ibft2ExtraData.decode(bufferToInject);
assertThat(extraData.getVanityData()).isEqualTo(vanity_data);
assertThat(extraData.getVote()).isEqualTo(vote);
assertThat(extraData.getRound()).isEqualTo(round);
assertThat(extraData.getSeals()).isEqualTo(committerSeals);
assertThat(extraData.getValidators()).isEqualTo(validators);
}
/**
* This test specifically verifies that {@link Ibft2ExtraData#decode(BytesValue)} uses {@link
* RLPInput#readInt()} rather than {@link RLPInput#readIntScalar()} to decode the round number
*/
@Test
public void incorrectlyEncodedRoundThrowsRlpException() {
final List<Address> validators = Lists.newArrayList();
final Optional<Vote> vote = Optional.of(Vote.authVote(Address.fromHexString("1")));
final byte[] roundAsByteArray = new byte[] {(byte) 0xFE, (byte) 0xDC, (byte) 0xBA};
final List<Signature> committerSeals = Lists.newArrayList();
// Create a byte buffer with no data.
final byte[] vanity_bytes = new byte[32];
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
final BytesValueRLPOutput encoder = new BytesValueRLPOutput();
encoder.startList();
encoder.writeBytesValue(vanity_data);
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator));
// encoded vote
encoder.startList();
encoder.writeBytesValue(vote.get().getRecipient());
vote.get().getVoteType().writeTo(encoder);
encoder.endList();
// This is to verify that the decoding throws an exception when the round number is not encoded
// in 4 byte format
encoder.writeBytesValue(BytesValue.wrap(roundAsByteArray));
encoder.writeList(
committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes()));
encoder.endList();
final BytesValue bufferToInject = encoder.encoded();
assertThatThrownBy(() -> Ibft2ExtraData.decode(bufferToInject))
.isInstanceOf(RLPException.class);
}
@Test
public void nullVoteAndListConstituteValidContent() {
final List<Address> validators = Lists.newArrayList();
final int round = 0x00FEDCBA;
final List<Signature> committerSeals = Lists.newArrayList();
// Create a byte buffer with no data.
final byte[] vanity_bytes = new byte[32];
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
final BytesValueRLPOutput encoder = new BytesValueRLPOutput();
encoder.startList();
encoder.writeBytesValue(vanity_data);
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator));
// encode an empty vote
encoder.writeNull();
encoder.writeInt(round);
encoder.writeList(
committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes()));
encoder.endList();
final BytesValue bufferToInject = encoder.encoded();
final Ibft2ExtraData extraData = Ibft2ExtraData.decode(bufferToInject);
assertThat(extraData.getVanityData()).isEqualTo(vanity_data);
assertThat(extraData.getVote().isPresent()).isEqualTo(false);
assertThat(extraData.getRound()).isEqualTo(round);
assertThat(extraData.getSeals()).isEqualTo(committerSeals);
assertThat(extraData.getValidators()).isEqualTo(validators);
}
@Test
public void emptyVoteAndListIsEncodedCorrectly() {
final List<Address> validators = Lists.newArrayList();
Optional<Vote> vote = Optional.empty();
final int round = 0x00FEDCBA;
final List<Signature> committerSeals = Lists.newArrayList();
// Create a byte buffer with no data.
final byte[] vanity_bytes = new byte[32];
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
Ibft2ExtraData expectedExtraData =
new Ibft2ExtraData(vanity_data, committerSeals, vote, round, validators);
Ibft2ExtraData actualExtraData = Ibft2ExtraData.decode(expectedExtraData.encode());
assertThat(actualExtraData).isEqualToComparingFieldByField(expectedExtraData);
}
@Test
public void emptyListConstituteValidContent() {
final List<Address> validators = Lists.newArrayList();
final Optional<Vote> vote = Optional.of(Vote.dropVote(Address.fromHexString("1")));
final int round = 0x00FEDCBA;
final List<Signature> committerSeals = Lists.newArrayList();
// Create a byte buffer with no data.
final byte[] vanity_bytes = new byte[32];
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
final BytesValueRLPOutput encoder = new BytesValueRLPOutput();
encoder.startList();
encoder.writeBytesValue(vanity_data);
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator));
// encoded vote
encoder.startList();
encoder.writeBytesValue(vote.get().getRecipient());
vote.get().getVoteType().writeTo(encoder);
encoder.endList();
encoder.writeInt(round);
encoder.writeList(
committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes()));
encoder.endList();
final BytesValue bufferToInject = encoder.encoded();
final Ibft2ExtraData extraData = Ibft2ExtraData.decode(bufferToInject);
assertThat(extraData.getVanityData()).isEqualTo(vanity_data);
assertThat(extraData.getVote()).isEqualTo(vote);
assertThat(extraData.getRound()).isEqualTo(round);
assertThat(extraData.getSeals()).isEqualTo(committerSeals);
assertThat(extraData.getValidators()).isEqualTo(validators);
}
@Test
public void emptyListsAreEncodedAndDecodedCorrectly() {
final List<Address> validators = Lists.newArrayList();
final Optional<Vote> vote = Optional.of(Vote.authVote(Address.fromHexString("1")));
final int round = 0x00FEDCBA;
final List<Signature> committerSeals = Lists.newArrayList();
// Create a byte buffer with no data.
final byte[] vanity_bytes = new byte[32];
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
Ibft2ExtraData expectedExtraData =
new Ibft2ExtraData(vanity_data, committerSeals, vote, round, validators);
Ibft2ExtraData actualExtraData = Ibft2ExtraData.decode(expectedExtraData.encode());
assertThat(actualExtraData).isEqualToComparingFieldByField(expectedExtraData);
}
@Test
public void fullyPopulatedDataProducesCorrectlyFormedExtraDataObject() {
final List<Address> validators =
Arrays.asList(Address.fromHexString("1"), Address.fromHexString("2"));
final Optional<Vote> vote = Optional.of(Vote.authVote(Address.fromHexString("1")));
final int round = 0x00FEDCBA;
final List<Signature> committerSeals =
Arrays.asList(
Signature.create(BigInteger.ONE, BigInteger.TEN, (byte) 0),
Signature.create(BigInteger.TEN, BigInteger.ONE, (byte) 0));
// Create randomised vanity data.
final byte[] vanity_bytes = createNonEmptyVanityData();
new Random().nextBytes(vanity_bytes);
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
final BytesValueRLPOutput encoder = new BytesValueRLPOutput();
encoder.startList(); // This is required to create a "root node" for all RLP'd data
encoder.writeBytesValue(vanity_data);
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator));
// encoded vote
encoder.startList();
encoder.writeBytesValue(vote.get().getRecipient());
vote.get().getVoteType().writeTo(encoder);
encoder.endList();
encoder.writeInt(round);
encoder.writeList(
committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes()));
encoder.endList();
final BytesValue bufferToInject = encoder.encoded();
final Ibft2ExtraData extraData = Ibft2ExtraData.decode(bufferToInject);
assertThat(extraData.getVanityData()).isEqualTo(vanity_data);
assertThat(extraData.getVote()).isEqualTo(vote);
assertThat(extraData.getRound()).isEqualTo(round);
assertThat(extraData.getSeals()).isEqualTo(committerSeals);
assertThat(extraData.getValidators()).isEqualTo(validators);
}
@Test
public void fullyPopulatedDataIsEncodedAndDecodedCorrectly() {
final List<Address> validators =
Arrays.asList(Address.fromHexString("1"), Address.fromHexString("2"));
final Optional<Vote> vote = Optional.of(Vote.authVote(Address.fromHexString("1")));
final int round = 0x00FEDCBA;
final List<Signature> committerSeals =
Arrays.asList(
Signature.create(BigInteger.ONE, BigInteger.TEN, (byte) 0),
Signature.create(BigInteger.TEN, BigInteger.ONE, (byte) 0));
// Create a byte buffer with no data.
final byte[] vanity_bytes = createNonEmptyVanityData();
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
Ibft2ExtraData expectedExtraData =
new Ibft2ExtraData(vanity_data, committerSeals, vote, round, validators);
Ibft2ExtraData actualExtraData = Ibft2ExtraData.decode(expectedExtraData.encode());
assertThat(actualExtraData).isEqualToComparingFieldByField(expectedExtraData);
}
@Test
public void encodingMatchesKnownRawHexString() {
BytesValue expectedRawDecoding = BytesValue.fromHexString(RAW_HEX_ENCODING_STRING);
assertThat(DECODED_EXTRA_DATA_FOR_RAW_HEX_ENCODING_STRING.encode())
.isEqualTo(expectedRawDecoding);
}
@Test
public void decodingOfKnownRawHexStringMatchesKnowExtraDataObject() {
final Ibft2ExtraData expectedExtraData = DECODED_EXTRA_DATA_FOR_RAW_HEX_ENCODING_STRING;
BytesValue rawDecoding = BytesValue.fromHexString(RAW_HEX_ENCODING_STRING);
Ibft2ExtraData actualExtraData = Ibft2ExtraData.decode(rawDecoding);
assertThat(actualExtraData).isEqualToComparingFieldByField(expectedExtraData);
}
@Test
public void incorrectlyStructuredRlpThrowsException() {
final List<Address> validators = Lists.newArrayList();
final Optional<Vote> vote = Optional.of(Vote.authVote(Address.fromHexString("1")));
final int round = 0x00FEDCBA;
final List<Signature> committerSeals = Lists.newArrayList();
// Create a byte buffer with no data.
final byte[] vanity_bytes = new byte[32];
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
final BytesValueRLPOutput encoder = new BytesValueRLPOutput();
encoder.startList();
encoder.writeBytesValue(vanity_data);
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator));
// encoded vote
encoder.startList();
encoder.writeBytesValue(vote.get().getRecipient());
vote.get().getVoteType().writeTo(encoder);
encoder.endList();
encoder.writeInt(round);
encoder.writeList(
committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes()));
encoder.writeLong(1);
encoder.endList();
final BytesValue bufferToInject = encoder.encoded();
assertThatThrownBy(() -> Ibft2ExtraData.decode(bufferToInject))
.isInstanceOf(RLPException.class);
}
@Test
public void incorrectVoteTypeThrowsException() {
final List<Address> validators =
Arrays.asList(Address.fromHexString("1"), Address.fromHexString("2"));
final Address voteRecipient = Address.fromHexString("1");
final byte voteType = (byte) 0xAA;
final int round = 0x00FEDCBA;
final List<Signature> committerSeals =
Arrays.asList(
Signature.create(BigInteger.ONE, BigInteger.TEN, (byte) 0),
Signature.create(BigInteger.TEN, BigInteger.ONE, (byte) 0));
// Create a byte buffer with no data.
final byte[] vanity_bytes = new byte[32];
final BytesValue vanity_data = BytesValue.wrap(vanity_bytes);
final BytesValueRLPOutput encoder = new BytesValueRLPOutput();
encoder.startList();
encoder.writeBytesValue(vanity_data);
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator));
// encode vote
encoder.startList();
encoder.writeBytesValue(voteRecipient);
encoder.writeByte(voteType);
encoder.endList();
encoder.writeInt(round);
encoder.writeList(
committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes()));
encoder.endList();
final BytesValue bufferToInject = encoder.encoded();
assertThatThrownBy(() -> Ibft2ExtraData.decode(bufferToInject))
.isInstanceOf(RLPException.class);
}
private static byte[] createNonEmptyVanityData() {
final byte[] vanity_bytes = new byte[32];
for (int i = 0; i < vanity_bytes.length; i++) {
vanity_bytes[i] = (byte) (i + 1);
}
return vanity_bytes;
}
}

@ -0,0 +1,30 @@
/*
* Copyright 2018 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.consensus.ibft;
import static org.assertj.core.api.Java6Assertions.assertThat;
import tech.pegasys.pantheon.ethereum.core.Address;
import org.junit.Test;
public class VoteTest {
@Test
public void testStaticVoteCreationMethods() {
assertThat(Vote.authVote(Address.fromHexString("1")).isAuth()).isEqualTo(true);
assertThat(Vote.authVote(Address.fromHexString("1")).isDrop()).isEqualTo(false);
assertThat(Vote.dropVote(Address.fromHexString("1")).isAuth()).isEqualTo(false);
assertThat(Vote.dropVote(Address.fromHexString("1")).isDrop()).isEqualTo(true);
}
}
Loading…
Cancel
Save