out.writeBytesValue(BytesValue.EMPTY); break; case 1: out.writeByte((byte) random.nextInt(128)); break; case 2: out.writeByte(value); break; case 3: out.writeBytesValue(randomBytesValue(random, smallBytesSize)); break; case 4: out.writeBytesValue(randomBytesValue(random, largeBytesSize)); break; case 5: out.endList(); listDepth.decrementAndGet(); break; default: out.startList(); listDepth.incrementAndGet(); break;
private static void encode(final Object obj, final RLPOutput out) { if (obj instanceof BytesValue) { out.writeBytesValue((BytesValue) obj); } else if (obj instanceof List) { final List<?> l = (List<?>) obj; out.startList(); for (final Object o : l) encode(o, out); out.endList(); } else { throw new IllegalArgumentException( format("Invalid input type %s for RLP encoding", obj.getClass())); } }
@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 IbftExtraData extraData = IbftExtraData.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 emptyListsConstituteValidContent() { final Signature proposerSeal = Signature.create(BigInteger.ONE, BigInteger.ONE, (byte) 0); final List<Address> validators = Lists.newArrayList(); final List<Signature> committerSeals = Lists.newArrayList(); final BytesValueRLPOutput encoder = new BytesValueRLPOutput(); encoder.startList(); encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator)); encoder.writeBytesValue(proposerSeal.encodedBytes()); encoder.writeList( committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes())); encoder.endList(); // Create a byte buffer with no data. final byte[] vanity_bytes = new byte[32]; final BytesValue vanity_data = BytesValue.wrap(vanity_bytes); final BytesValue bufferToInject = BytesValue.wrap(vanity_data, encoder.encoded()); final IbftExtraData extraData = IbftExtraData.decode(bufferToInject); Assertions.assertThat(extraData.getVanityData()).isEqualTo(vanity_data); assertThat(extraData.getProposerSeal()).isEqualTo(proposerSeal); Assertions.assertThat(extraData.getSeals()).isEqualTo(committerSeals); Assertions.assertThat(extraData.getValidators()).isEqualTo(validators); }
@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 vote.get().writeTo(encoder); encoder.writeInt(round); encoder.writeList( committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes())); encoder.writeLong(1); encoder.endList(); final BytesValue bufferToInject = encoder.encoded(); assertThatThrownBy(() -> IbftExtraData.decode(bufferToInject)).isInstanceOf(RLPException.class); }
@Test public void fullyPopulatedDataProducesCorrectlyFormedExtraDataObject() { final List<Address> validators = Arrays.asList(Address.ECREC, Address.SHA256); final Signature proposerSeal = Signature.create(BigInteger.ONE, BigInteger.ONE, (byte) 0); final List<Signature> committerSeals = Arrays.asList( Signature.create(BigInteger.ONE, BigInteger.TEN, (byte) 0), Signature.create(BigInteger.TEN, BigInteger.ONE, (byte) 0)); final BytesValueRLPOutput encoder = new BytesValueRLPOutput(); encoder.startList(); // This is required to create a "root node" for all RLP'd data encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator)); encoder.writeBytesValue(proposerSeal.encodedBytes()); encoder.writeList( committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes())); encoder.endList(); // Create randomised vanity data. final byte[] vanity_bytes = new byte[32]; new Random().nextBytes(vanity_bytes); final BytesValue vanity_data = BytesValue.wrap(vanity_bytes); final BytesValue bufferToInject = BytesValue.wrap(vanity_data, encoder.encoded()); final IbftExtraData extraData = IbftExtraData.decode(bufferToInject); Assertions.assertThat(extraData.getVanityData()).isEqualTo(vanity_data); assertThat(extraData.getProposerSeal()).isEqualTo(proposerSeal); Assertions.assertThat(extraData.getSeals()).isEqualTo(committerSeals); Assertions.assertThat(extraData.getValidators()).isEqualTo(validators); }
@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 vote.get().writeTo(encoder); encoder.writeInt(round); encoder.writeList( committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes())); encoder.endList(); final BytesValue bufferToInject = encoder.encoded(); final IbftExtraData extraData = IbftExtraData.decode(bufferToInject); assertThat(extraData.getVanityData()).isEqualTo(vanity_data); assertThat(extraData.getRound()).isEqualTo(round); assertThat(extraData.getSeals()).isEqualTo(committerSeals); assertThat(extraData.getValidators()).isEqualTo(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 vote.get().writeTo(encoder); // 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 IbftExtraData extraData = IbftExtraData.decode(bufferToInject); assertThat(extraData.getVanityData()).isEqualTo(vanity_data); assertThat(extraData.getRound()).isEqualTo(round); assertThat(extraData.getSeals()).isEqualTo(committerSeals); assertThat(extraData.getValidators()).isEqualTo(validators); }
/** * This test specifically verifies that {@link IbftExtraData#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 vote.get().writeTo(encoder); // 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(() -> IbftExtraData.decode(bufferToInject)).isInstanceOf(RLPException.class); }
@Test(expected = RLPException.class) public void incorrectlyStructuredRlpThrowsException() { final Signature proposerSeal = Signature.create(BigInteger.ONE, BigInteger.ONE, (byte) 0); final List<Address> validators = Lists.newArrayList(); final List<Signature> committerSeals = Lists.newArrayList(); final BytesValueRLPOutput encoder = new BytesValueRLPOutput(); encoder.startList(); encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator)); encoder.writeBytesValue(proposerSeal.encodedBytes()); encoder.writeList( committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes())); encoder.writeLong(1); encoder.endList(); final BytesValue bufferToInject = BytesValue.wrap(BytesValue.wrap(new byte[32]), encoder.encoded()); IbftExtraData.decode(bufferToInject); }
@Test(expected = RLPException.class) public void incorrectlySizedVanityDataThrowsException() { final List<Address> validators = Arrays.asList(Address.ECREC, Address.SHA256); final Signature proposerSeal = Signature.create(BigInteger.ONE, BigInteger.ONE, (byte) 0); final List<Signature> committerSeals = Arrays.asList( Signature.create(BigInteger.ONE, BigInteger.TEN, (byte) 0), Signature.create(BigInteger.TEN, BigInteger.ONE, (byte) 0)); final BytesValueRLPOutput encoder = new BytesValueRLPOutput(); encoder.startList(); encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator)); encoder.writeBytesValue(proposerSeal.encodedBytes()); encoder.writeList( committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes())); encoder.endList(); final BytesValue bufferToInject = BytesValue.wrap(BytesValue.wrap(new byte[31]), encoder.encoded()); IbftExtraData.decode(bufferToInject); }
@Test public void extraDataCanBeEncodedwithoutCommitSealsOrRoundNumber() { 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); final BytesValueRLPOutput encoder = new BytesValueRLPOutput(); encoder.startList(); encoder.writeBytesValue(vanity_data); encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator)); // encoded vote vote.get().writeTo(encoder); encoder.endList(); BytesValue expectedEncoding = encoder.encoded(); BytesValue actualEncoding = new IbftExtraData(vanity_data, committerSeals, vote, round, validators) .encodeWithoutCommitSealsAndRoundNumber(); assertThat(actualEncoding).isEqualTo(expectedEncoding); }
encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator)); committerSeals, (committer, rlp) -> rlp.writeBytesValue(committer.encodedBytes())); encoder.endList();
@Test public void extraDataCanBeEncodedWithoutCommitSeals() { 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); final BytesValueRLPOutput encoder = new BytesValueRLPOutput(); encoder.startList(); encoder.writeBytesValue(vanity_data); encoder.writeList(validators, (validator, rlp) -> rlp.writeBytesValue(validator)); // encoded vote vote.get().writeTo(encoder); encoder.writeInt(round); encoder.endList(); BytesValue expectedEncoding = encoder.encoded(); BytesValue actualEncoding = new IbftExtraData(vanity_data, committerSeals, vote, round, validators) .encodeWithoutCommitSeals(); assertThat(actualEncoding).isEqualTo(expectedEncoding); }
@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(() -> IbftExtraData.decode(bufferToInject)).isInstanceOf(RLPException.class); }