Skip to content

Commit 92e186a

Browse files
Support clearing node grpc proxy endpoint (#11587)
Support clearing the node.grpc_proxy_endpoint when ServiceEndpoint.getDefaultInstance() is set Signed-off-by: Steven Sheehy <[email protected]>
1 parent cf01b1a commit 92e186a

File tree

5 files changed

+76
-20
lines changed

5 files changed

+76
-20
lines changed

common/src/main/java/org/hiero/mirror/common/domain/node/AbstractNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public abstract class AbstractNode implements History {
3737

3838
@JsonSerialize(using = ObjectToStringSerializer.class)
3939
@JdbcTypeCode(SqlTypes.JSON)
40-
@UpsertColumn(shouldCoalesce = false)
40+
@UpsertColumn(coalesce = "case when ({0} -> ''port'')::integer = -1 then null else coalesce({0}, e_{0}) end")
4141
private ServiceEndpoint grpcProxyEndpoint;
4242

4343
@Id

common/src/main/java/org/hiero/mirror/common/domain/node/ServiceEndpoint.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
import lombok.Builder;
66

77
@Builder(toBuilder = true)
8-
public record ServiceEndpoint(String domainName, String ipAddressV4, int port) {}
8+
public record ServiceEndpoint(String domainName, String ipAddressV4, int port) {
9+
public static final ServiceEndpoint CLEAR = new ServiceEndpoint(null, null, -1);
10+
}

importer/src/main/java/org/hiero/mirror/importer/parser/record/transactionhandler/AbstractNodeTransactionHandler.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ protected void doUpdateTransaction(Transaction transaction, RecordItem recordIte
3535

3636
protected final ServiceEndpoint toServiceEndpoint(
3737
long consensusTimestamp, com.hederahashgraph.api.proto.java.ServiceEndpoint proto) {
38+
39+
// This won't happen for node create since consensus nodes reject default ServiceEndpoint
40+
if (com.hederahashgraph.api.proto.java.ServiceEndpoint.getDefaultInstance()
41+
.equals(proto)) {
42+
return ServiceEndpoint.CLEAR;
43+
}
44+
3845
String ipAddress = StringUtils.EMPTY;
3946

4047
try {

importer/src/test/java/org/hiero/mirror/importer/parser/record/entity/EntityRecordItemListenerNodeTest.java

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.hiero.mirror.common.domain.addressbook.NodeStake;
1515
import org.hiero.mirror.common.domain.node.Node;
1616
import org.hiero.mirror.common.domain.node.ServiceEndpoint;
17-
import org.hiero.mirror.common.domain.transaction.RecordItem;
1817
import org.hiero.mirror.common.domain.transaction.Transaction;
1918
import org.hiero.mirror.common.util.DomainUtils;
2019
import org.hiero.mirror.importer.repository.NetworkStakeRepository;
@@ -24,20 +23,12 @@
2423
import org.junit.jupiter.api.Test;
2524

2625
@RequiredArgsConstructor
27-
class EntityRecordItemListenerNodeTest extends AbstractEntityRecordItemListenerTest {
26+
final class EntityRecordItemListenerNodeTest extends AbstractEntityRecordItemListenerTest {
2827

2928
private final NodeRepository nodeRepository;
3029
private final NetworkStakeRepository networkStakeRepository;
3130
private final NodeStakeRepository nodeStakeRepository;
3231

33-
private static Node.NodeBuilder<?, ?> getExpectedNode(RecordItem recordItem) {
34-
return Node.builder()
35-
.createdTimestamp(recordItem.getConsensusTimestamp())
36-
.declineReward(false)
37-
.nodeId(recordItem.getTransactionRecord().getReceipt().getNodeId())
38-
.timestampRange(Range.atLeast(recordItem.getConsensusTimestamp()));
39-
}
40-
4132
@SuppressWarnings("deprecation")
4233
@Test
4334
void nodeStakeUpdate() {
@@ -101,13 +92,17 @@ void nodeCreate() {
10192
var recordItem = recordItemBuilder.nodeCreate().build();
10293
var nodeCreate = recordItem.getTransactionBody().getNodeCreate();
10394
var protoEndpoint = nodeCreate.getGrpcProxyEndpoint();
104-
var expectedNode = getExpectedNode(recordItem)
95+
var expectedNode = Node.builder()
10596
.adminKey(nodeCreate.getAdminKey().toByteArray())
97+
.createdTimestamp(recordItem.getConsensusTimestamp())
98+
.declineReward(false)
10699
.grpcProxyEndpoint(ServiceEndpoint.builder()
107100
.domainName(protoEndpoint.getDomainName())
108101
.ipAddressV4("")
109102
.port(protoEndpoint.getPort())
110103
.build())
104+
.nodeId(recordItem.getTransactionRecord().getReceipt().getNodeId())
105+
.timestampRange(Range.atLeast(recordItem.getConsensusTimestamp()))
111106
.build();
112107

113108
parseRecordItemAndCommit(recordItem);
@@ -162,12 +157,42 @@ void nodeUpdate() {
162157
softly.assertThat(findHistory(Node.class)).containsExactly(node);
163158
}
164159

160+
@Test
161+
void nodeUpdateUnsetGrpcProxyEndpoint() {
162+
var recordItem = recordItemBuilder
163+
.nodeUpdate()
164+
.transactionBody(b -> b.clearAdminKey()
165+
.setGrpcProxyEndpoint(com.hederahashgraph.api.proto.java.ServiceEndpoint.getDefaultInstance()))
166+
.build();
167+
var nodeUpdate = recordItem.getTransactionBody().getNodeUpdate();
168+
var timestamp = recordItem.getConsensusTimestamp() - 1;
169+
var node = domainBuilder
170+
.node()
171+
.customize(n -> n.createdTimestamp(timestamp)
172+
.nodeId(nodeUpdate.getNodeId())
173+
.timestampRange(Range.atLeast(timestamp)))
174+
.persist();
175+
176+
var expectedNode = node.toBuilder()
177+
.grpcProxyEndpoint(null) // Should clear
178+
.timestampRange(Range.atLeast(recordItem.getConsensusTimestamp()))
179+
.build();
180+
181+
parseRecordItemAndCommit(recordItem);
182+
183+
node.setTimestampUpper(recordItem.getConsensusTimestamp());
184+
185+
softly.assertThat(nodeRepository.findAll()).containsExactly(expectedNode);
186+
softly.assertThat(findHistory(Node.class)).containsExactly(node);
187+
}
188+
165189
@Test
166190
void nodeUpdateNoChange() {
167191
var recordItem = recordItemBuilder
168192
.nodeUpdate()
169193
.transactionBody(NodeUpdateTransactionBody.Builder::clearAdminKey)
170194
.transactionBody(NodeUpdateTransactionBody.Builder::clearDeclineReward)
195+
.transactionBody(NodeUpdateTransactionBody.Builder::clearGrpcProxyEndpoint)
171196
.build();
172197
var nodeUpdate = recordItem.getTransactionBody().getNodeUpdate();
173198
var timestamp = recordItem.getConsensusTimestamp() - 1;
@@ -211,10 +236,9 @@ void nodeDelete() {
211236
.receipt(r -> r.setNodeId(node.getNodeId()))
212237
.transactionBody(b -> b.setNodeId(node.getNodeId()))
213238
.build();
214-
var expectedNode = getExpectedNode(recordItem)
215-
.adminKey(node.getAdminKey())
216-
.createdTimestamp(node.getCreatedTimestamp())
239+
var deletedNode = node.toBuilder()
217240
.deleted(true)
241+
.timestampRange(Range.atLeast(recordItem.getConsensusTimestamp()))
218242
.build();
219243

220244
parseRecordItemAndCommit(recordItem);
@@ -228,7 +252,7 @@ void nodeDelete() {
228252
.isNotNull()
229253
.returns(recordItem.getTransaction().toByteArray(), Transaction::getTransactionBytes)
230254
.returns(recordItem.getTransactionRecord().toByteArray(), Transaction::getTransactionRecordBytes);
231-
softly.assertThat(nodeRepository.findAll()).containsExactly(expectedNode);
255+
softly.assertThat(nodeRepository.findAll()).containsExactly(deletedNode);
232256
softly.assertThat(findHistory(Node.class)).containsExactly(node);
233257
}
234258
}

importer/src/test/java/org/hiero/mirror/importer/parser/record/transactionhandler/NodeUpdateTransactionHandlerTest.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
import com.hederahashgraph.api.proto.java.TransactionID;
1212
import org.hiero.mirror.common.domain.entity.EntityType;
1313
import org.hiero.mirror.common.domain.node.Node;
14+
import org.hiero.mirror.common.domain.node.ServiceEndpoint;
1415
import org.junit.jupiter.api.Test;
1516

16-
class NodeUpdateTransactionHandlerTest extends AbstractTransactionHandlerTest {
17+
final class NodeUpdateTransactionHandlerTest extends AbstractTransactionHandlerTest {
1718

1819
@Override
1920
protected TransactionHandler getTransactionHandler() {
@@ -57,7 +58,27 @@ void nodeUpdate() {
5758
.returns(adminKey, Node::getAdminKey)
5859
.returns(null, Node::getCreatedTimestamp)
5960
.returns(recordItem.getConsensusTimestamp(), Node::getTimestampLower)
60-
.returns(false, Node::isDeleted)));
61+
.returns(false, Node::isDeleted)
62+
.returns(new ServiceEndpoint("node1.hedera.com", "", 80), Node::getGrpcProxyEndpoint)));
63+
}
64+
65+
@Test
66+
void nodeUpdateClearGrpcProxyEndpoint() {
67+
// given
68+
var recordItem = recordItemBuilder
69+
.nodeUpdate()
70+
.transactionBody(b ->
71+
b.setGrpcProxyEndpoint(com.hederahashgraph.api.proto.java.ServiceEndpoint.getDefaultInstance()))
72+
.build();
73+
var transaction = domainBuilder.transaction().get();
74+
75+
// when
76+
transactionHandler.updateTransaction(transaction, recordItem);
77+
78+
// then
79+
verify(entityListener, times(1))
80+
.onNode(assertArg(
81+
t -> assertThat(t).isNotNull().returns(ServiceEndpoint.CLEAR, Node::getGrpcProxyEndpoint)));
6182
}
6283

6384
@Test
@@ -93,6 +114,7 @@ void nodeUpdateMissingFields() {
93114
.nodeUpdate()
94115
.transactionBody(NodeUpdateTransactionBody.Builder::clearAdminKey)
95116
.transactionBody(NodeUpdateTransactionBody.Builder::clearDeclineReward)
117+
.transactionBody(NodeUpdateTransactionBody.Builder::clearGrpcProxyEndpoint)
96118
.build();
97119
var transaction = domainBuilder.transaction().get();
98120

@@ -112,6 +134,7 @@ void nodeUpdateMissingFields() {
112134
.returns(null, Node::getAdminKey)
113135
.returns(null, Node::getDeclineReward)
114136
.returns(recordItem.getConsensusTimestamp(), Node::getTimestampLower)
115-
.returns(false, Node::isDeleted)));
137+
.returns(false, Node::isDeleted)
138+
.returns(null, Node::getGrpcProxyEndpoint)));
116139
}
117140
}

0 commit comments

Comments
 (0)