Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: return AddressBook from AddressBookRoster #11511

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,39 @@ private static final class ClassVersion {

private final Map<NodeId, RosterEntry> entries = new HashMap<>();
private List<NodeId> nodeOrder;
private AddressBook addressBook;

/**
* Constructs a new {@link AddressBookRoster} from the given {@link AddressBook} and {@link KeysAndCerts} map.
*
* @param addressBook the address book
* @param keysAndCertsMap the keys and certs map
*/
public AddressBookRoster(
@NonNull final AddressBook addressBook, @NonNull final Map<NodeId, KeysAndCerts> keysAndCertsMap) {
Objects.requireNonNull(addressBook);
Objects.requireNonNull(keysAndCertsMap);
public AddressBookRoster(@NonNull final AddressBook addressBook) {
this.addressBook = Objects.requireNonNull(addressBook);
setupRosterFromAddressBook();
}

/**
* Populates the AddressRosterEntry map from the AddressBook and determines the node order.
*/
private void setupRosterFromAddressBook() {
for (final Address address : addressBook) {
entries.put(address.getNodeId(), new AddressRosterEntry(address, keysAndCertsMap.get(address.getNodeId())));
entries.put(address.getNodeId(), new AddressRosterEntry(address));
}

nodeOrder = entries.keySet().stream().sorted().toList();
}

/**
* Returns the address book.
*
* @return the address book
*/
@NonNull
public AddressBook getAddressBook() {
return addressBook;
}

/**
* Empty constructor for deserialization.
*/
Expand All @@ -87,20 +101,13 @@ public int getVersion() {

@Override
public void serialize(@NonNull final SerializableDataOutputStream out) throws IOException {
out.writeInt(entries.size());
for (final RosterEntry entry : this) {
out.writeSerializable(entry, true);
}
out.writeSerializable(addressBook, false);
}

@Override
public void deserialize(@NonNull final SerializableDataInputStream in, final int version) throws IOException {
final int size = in.readInt();
for (int i = 0; i < size; i++) {
final RosterEntry entry = in.readSerializable();
entries.put(entry.getNodeId(), entry);
}
nodeOrder = entries.keySet().stream().sorted().toList();
addressBook = in.readSerializable(false, AddressBook::new);
setupRosterFromAddressBook();
}

@Override
Expand Down Expand Up @@ -147,12 +154,14 @@ public boolean equals(@Nullable final Object o) {
return false;
}
final AddressBookRoster that = (AddressBookRoster) o;
return Objects.equals(entries, that.entries);
return Objects.equals(addressBook, that.addressBook)
&& Objects.equals(entries, that.entries)
&& Objects.equals(nodeOrder, that.nodeOrder);
}

@Override
public int hashCode() {
return Objects.hash(entries);
return Objects.hash(addressBook);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@
import com.swirlds.platform.system.address.Address;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Objects;

Expand All @@ -44,30 +40,32 @@ private static final class ClassVersion {
public static final int ORIGINAL = 1;
}

private static final int ENCODED_CERT_MAX_SIZE = 8192;

private Address address;
private X509Certificate sigCert;

/**
* Constructs a new {@link AddressRosterEntry} from the given {@link Address} and {@link KeysAndCerts}.
*
* @param address the address
* @param keysAndCerts the keys and certs containing the signing certificate
* @param address the address
*/
public AddressRosterEntry(@NonNull final Address address, @NonNull final KeysAndCerts keysAndCerts) {
Objects.requireNonNull(address);
Objects.requireNonNull(keysAndCerts);

this.address = address;
this.sigCert = keysAndCerts.sigCert();
public AddressRosterEntry(@NonNull final Address address) {
this.address = Objects.requireNonNull(address);
}

/**
* Empty constructor for deserialization.
*/
public AddressRosterEntry() {}

/**
* Returns the address.
*
* @return the address
*/
@NonNull
public Address getAddress() {
return address;
}

/**
* {@inheritDoc}
*/
Expand All @@ -87,23 +85,11 @@ public int getVersion() {
@Override
public void serialize(@NonNull final SerializableDataOutputStream out) throws IOException {
out.writeSerializable(address, false);
try {
out.writeByteArray(sigCert.getEncoded());
} catch (final CertificateEncodingException e) {
throw new IOException("Could not encode certificate", e);
}
}

@Override
public void deserialize(@NonNull final SerializableDataInputStream in, final int version) throws IOException {
address = in.readSerializable(false, Address::new);
final byte[] encodedCert = in.readByteArray(ENCODED_CERT_MAX_SIZE);
try {
sigCert = (X509Certificate)
CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(encodedCert));
} catch (final CertificateException e) {
throw new IOException("Could not decode certificate", e);
}
}

@Override
Expand Down Expand Up @@ -131,7 +117,7 @@ public int getPort() {
@NonNull
@Override
public X509Certificate getSigningCertificate() {
return sigCert;
return Objects.requireNonNull(address.getSigCert());
}

@Override
Expand All @@ -143,20 +129,17 @@ public boolean equals(@Nullable final Object o) {
return false;
}
final AddressRosterEntry that = (AddressRosterEntry) o;
return Objects.equals(address, that.address) && Objects.equals(sigCert, that.sigCert);
return Objects.equals(address, that.address);
}

@Override
public int hashCode() {
return Objects.hash(address, sigCert);
return Objects.hash(address);
}

@Override
public String toString() {

return new ToStringBuilder(this)
.append("address", address)
.append("sigCert", sigCert)
.toString();
return new ToStringBuilder(this).append("address", address).toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,27 @@
import com.swirlds.common.io.streams.SerializableDataInputStream;
import com.swirlds.common.io.streams.SerializableDataOutputStream;
import com.swirlds.common.platform.NodeId;
import com.swirlds.platform.crypto.KeysAndCerts;
import com.swirlds.platform.roster.Roster;
import com.swirlds.platform.roster.RosterEntry;
import com.swirlds.platform.system.address.Address;
import com.swirlds.platform.system.address.AddressBook;
import edu.umd.cs.findbugs.annotations.NonNull;
import com.swirlds.platform.test.fixtures.addressbook.RandomAddressBookGenerator;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.api.Test;

public class AddressBookRosterTests {

@Test
@DisplayName("Serialize and deserialize AddressBook derived Roster")
@ParameterizedTest
@MethodSource({"com.swirlds.platform.crypto.CryptoArgsProvider#basicTestArgs"})
void serializeDeserializeTest(
@NonNull final AddressBook addressBook, @NonNull final Map<NodeId, KeysAndCerts> keysAndCerts)
throws IOException, ConstructableRegistryException {
void serializeDeserializeTest() throws IOException, ConstructableRegistryException {
final AddressBook addressBook =
new RandomAddressBookGenerator().setSize(100).build();
ConstructableRegistry.getInstance().registerConstructables("com.swirlds");
final Roster roster = new AddressBookRoster(addressBook, keysAndCerts);
final AddressBookRoster roster = new AddressBookRoster(addressBook);

final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
final SerializableDataOutputStream out = new SerializableDataOutputStream(byteOut);
Expand All @@ -58,16 +54,17 @@ void serializeDeserializeTest(
final SerializableDataInputStream in =
new SerializableDataInputStream(new ByteArrayInputStream(byteOut.toByteArray()));

Roster roster2 = in.readSerializable();
final AddressBookRoster roster2 = in.readSerializable();
assertEquals(roster, roster2);
assertEquals(addressBook, roster2.getAddressBook());
}

@Test
@DisplayName("Roster derived from AddressBook")
@ParameterizedTest
@MethodSource({"com.swirlds.platform.crypto.CryptoArgsProvider#basicTestArgs"})
void addressBookRosterTest(
@NonNull final AddressBook addressBook, @NonNull final Map<NodeId, KeysAndCerts> keysAndCerts) {
final Roster roster = new AddressBookRoster(addressBook, keysAndCerts);
void addressBookRosterTest() {
final AddressBook addressBook =
new RandomAddressBookGenerator().setSize(100).build();
final Roster roster = new AddressBookRoster(addressBook);
final Iterator<RosterEntry> entries = roster.iterator();
for (int i = 0; i < addressBook.getSize(); i++) {
final NodeId nodeId = addressBook.getNodeId(i);
Expand All @@ -81,4 +78,28 @@ void addressBookRosterTest(
}
assertFalse(entries.hasNext());
}

@Test
@DisplayName("Serialize and deserialize AddressBook derived Roster")
void serializeDeserializeEntryTest() throws IOException, ConstructableRegistryException {
final AddressBook addressBook =
new RandomAddressBookGenerator().setSize(100).build();
ConstructableRegistry.getInstance().registerConstructables("com.swirlds");
final Roster roster = new AddressBookRoster(addressBook);

for (final RosterEntry entry : roster) {

final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
final SerializableDataOutputStream out = new SerializableDataOutputStream(byteOut);

out.writeSerializable(entry, true);

final SerializableDataInputStream in =
new SerializableDataInputStream(new ByteArrayInputStream(byteOut.toByteArray()));

RosterEntry entry2 = in.readSerializable();
assertEquals(entry, entry2);
assertEquals(addressBook.getAddress(entry.getNodeId()), ((AddressRosterEntry) entry2).getAddress());
}
}
}