Skip to content

Commit

Permalink
Add a get address book nodes gRPC API (#3141)
Browse files Browse the repository at this point in the history
* Add a NetworkService.getNodes() gRPC API
* Change AddressBookEntry and AddressBookServiceEndpoint to use @IdClass with flattened properties
* Change TopicMessageFilter to use EntityId instead of long
* Fix AddressBookServiceEndpoint incorrectly modeling nodeId as EntityId
* Move DomainBuilder to common module

Signed-off-by: Steven Sheehy <steven.sheehy@hedera.com>
Signed-off-by: Matheus DallRosa <matheus.dallrosa@swirlds.com>
  • Loading branch information
steven-sheehy authored and matheus-dallrosa committed Feb 21, 2022
1 parent b8dd1dd commit c295ba6
Show file tree
Hide file tree
Showing 75 changed files with 1,837 additions and 782 deletions.
69 changes: 37 additions & 32 deletions docs/configuration.md

Large diffs are not rendered by default.

29 changes: 27 additions & 2 deletions docs/grpc/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
# gRPC API

The gRPC API provides a protobuf defined interface for interacting with the mirror node. Currently only the Hedera
Consensus Service (HCS) topic subscription is supported.
The gRPC API provides a protobuf defined interface for interacting with the mirror node.

## Consensus Service

### Subscribe Topic

The Hedera Consensus Service (HCS) provides decentralized consensus on the validity and order of messages submitted to a
topic on the network and transparency into the history of these events over time. The `subscribeTopic` API allows a
client to subscribe to a topic and stream messages asynchronously as they arrive at the mirror node. See the protobuf
[definition](hedera-mirror-protobuf/src/main/proto/com/hedera/mirror/api/proto/consensus_service.proto).

Example invocation using [grpcurl](https://github.com/fullstorydev/grpcurl):

`grpcurl -plaintext -d '{"topicID": {"topicNum": 41110}, "limit": 0}' localhost:5600 com.hedera.mirror.api.proto.ConsensusService/subscribeTopic`

## Network Service

### Get Nodes

[HIP-21](https://hips.hedera.com/hip/hip-21) describes a need for clients to retrieve address book information without
incurring the costs of multiple queries to get the network file's contents. The `getNode` API will return the list of
nodes associated with the latest address book file. See the protobuf
[definition](/hedera-mirror-protobuf/src/main/proto/com/hedera/mirror/api/proto/network_service.proto).

Example invocation using `grpcurl`:

`grpcurl -plaintext -d '{"file_id": {"fileNum": 102}, "limit": 0}' localhost:5600 com.hedera.mirror.api.proto.NetworkService/getNodes`
12 changes: 12 additions & 0 deletions hedera-mirror-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import com.hedera.mirror.common.domain.entity.EntityId;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand All @@ -45,12 +43,13 @@
import lombok.ToString;

import com.hedera.mirror.common.converter.FileIdConverter;
import com.hedera.mirror.common.domain.entity.EntityId;

@Builder(toBuilder = true)
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE) // For builder
public class AddressBook {
// consensusTimestamp + 1ns of transaction containing final fileAppend operation
@Id
Expand All @@ -59,25 +58,25 @@ public class AddressBook {
// consensusTimestamp of transaction containing final fileAppend operation of next address book
private Long endConsensusTimestamp;

@OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "consensusTimestamp")
private List<AddressBookEntry> entries = new ArrayList<>();

@ToString.Exclude
private byte[] fileData;

@Convert(converter = FileIdConverter.class)
private EntityId fileId;

private Integer nodeCount;

@ToString.Exclude
private byte[] fileData;

@ToString.Exclude
@Transient
@Getter(lazy = true)
private final Map<String, PublicKey> nodeAccountIDPubKeyMap = this.getEntries()
.stream()
.collect(Collectors
.toMap(AddressBookEntry::getNodeAccountIdString, AddressBookEntry::getPublicKeyAsObject));

@OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "consensusTimestamp")
private List<AddressBookEntry> entries = new ArrayList<>();
.toMap(e -> e.getNodeAccountId().toString(), AddressBookEntry::getPublicKeyAsObject));

public Set<EntityId> getNodeSet() {
return entries.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import com.hedera.mirror.common.domain.entity.EntityId;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand All @@ -55,28 +57,30 @@
@Builder(toBuilder = true)
@Data
@Entity
@IdClass(AddressBookEntry.Id.class)
@NoArgsConstructor
@AllArgsConstructor
@ToString(exclude = {"publicKey", "nodeCertHash"})
public class AddressBookEntry implements Persistable<AddressBookEntry.Id>, Serializable {
private static final long serialVersionUID = -2037596800253225229L;
@AllArgsConstructor(access = AccessLevel.PRIVATE) // For builder
public class AddressBookEntry implements Persistable<AddressBookEntry.Id> {

@JsonIgnore
@EmbeddedId
@JsonUnwrapped
private AddressBookEntry.Id id;
@javax.persistence.Id
private long consensusTimestamp;

private String description;

private String memo;

private String publicKey;
@javax.persistence.Id
private long nodeId;

@Convert(converter = AccountIdConverter.class)
private EntityId nodeAccountId;

@ToString.Exclude
private byte[] nodeCertHash;

@ToString.Exclude
private String publicKey;

@EqualsAndHashCode.Exclude
@JoinColumn(name = "consensusTimestamp", referencedColumnName = "consensusTimestamp")
@JoinColumn(name = "nodeId", referencedColumnName = "nodeId")
Expand All @@ -97,9 +101,13 @@ public PublicKey getPublicKeyAsObject() {
}
}

@Transient
public String getNodeAccountIdString() {
return nodeAccountId.entityIdToString();
@JsonIgnore
@Override
public AddressBookEntry.Id getId() {
AddressBookEntry.Id id = new AddressBookEntry.Id();
id.setConsensusTimestamp(consensusTimestamp);
id.setNodeId(nodeId);
return id;
}

@JsonIgnore
Expand All @@ -109,9 +117,6 @@ public boolean isNew() {
}

@Data
@Embeddable
@AllArgsConstructor
@NoArgsConstructor
public static class Id implements Serializable {

private static final long serialVersionUID = -3761184325551298389L;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,48 @@
*/

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

import com.hedera.mirror.common.domain.entity.EntityId;

import javax.persistence.IdClass;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.domain.Persistable;

import com.hedera.mirror.common.converter.AccountIdConverter;

@Builder(toBuilder = true)
@Data
@Entity
@IdClass(AddressBookServiceEndpoint.Id.class)
@NoArgsConstructor
@AllArgsConstructor
public class AddressBookServiceEndpoint implements Persistable<AddressBookServiceEndpoint.Id>, Serializable {
@AllArgsConstructor(access = AccessLevel.PRIVATE) // For builder
public class AddressBookServiceEndpoint implements Persistable<AddressBookServiceEndpoint.Id> {

private static final long serialVersionUID = 6964963511683419945L;
@javax.persistence.Id
private long consensusTimestamp;

public AddressBookServiceEndpoint(long consensusTimestamp, String ip, int port, EntityId nodeAccountId) {
id = new AddressBookServiceEndpoint.Id(consensusTimestamp, ip, nodeAccountId, port);
}
@javax.persistence.Id
@Column(name = "ip_address_v4")
private String ipAddressV4;

@javax.persistence.Id
private long nodeId;

@javax.persistence.Id
private int port;

@JsonIgnore
@EmbeddedId
@JsonUnwrapped
private Id id;
@Override
public Id getId() {
Id id = new Id();
id.setConsensusTimestamp(consensusTimestamp);
id.setIpAddressV4(ipAddressV4);
id.setNodeId(nodeId);
id.setPort(port);
return id;
}

@JsonIgnore
@Override
Expand All @@ -62,9 +71,6 @@ public boolean isNew() {
}

@Data
@Embeddable
@AllArgsConstructor
@NoArgsConstructor
public static class Id implements Serializable {

private static final long serialVersionUID = -7779136597707252814L;
Expand All @@ -74,8 +80,7 @@ public static class Id implements Serializable {
@Column(name = "ip_address_v4")
private String ipAddressV4;

@Convert(converter = AccountIdConverter.class)
private EntityId nodeId;
private long nodeId;

private int port;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,20 @@ public static boolean isEmpty(EntityId entityId) {
return entityId == null || EMPTY.equals(entityId);
}

/**
* @deprecated in favor of using toString()
*/
@Deprecated(since = "v0.49.0")
public String entityIdToString() {
return String.format("%d.%d.%d", getShardNum(),
getRealmNum(), getEntityNum());
}

@SuppressWarnings("deprecation")
public String toString() {
return entityIdToString();
}

public <T extends AbstractEntity> T toEntity() {
T entity = createEntity();
entity.setId(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static Long encode(long shardNum, long realmNum, long entityNum) {
if (shardNum > SHARD_MASK || shardNum < 0 ||
realmNum > REALM_MASK || realmNum < 0 ||
entityNum > NUM_MASK || entityNum < 0) {
throw new InvalidEntityException("Entity outside encoding range: "
throw new InvalidEntityException("Invalid entity ID: "
+ shardNum + "." + realmNum + "." + entityNum);
}
return (entityNum & NUM_MASK) |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;

@Getter
@RequiredArgsConstructor
Expand All @@ -39,13 +40,16 @@ public enum EntityType {
TOKEN(5),
SCHEDULE(6);

private final int id;

private static final Map<Integer, EntityType> ID_MAP = Arrays.stream(values())
.collect(Collectors.toUnmodifiableMap(EntityType::getId, Function
.identity()));
.collect(Collectors.toUnmodifiableMap(EntityType::getId, Function.identity()));

private final int id;

public static EntityType fromId(int id) {
return ID_MAP.getOrDefault(id, UNKNOWN);
}

public String toDisplayString() {
return StringUtils.capitalize(name().toLowerCase());
}
}
Loading

0 comments on commit c295ba6

Please sign in to comment.