Skip to content

Incorrect field mappings in GRPC GetStatsInfo and GetNodeInfo #6926

Description

@xxo1shine

Summary

Two GRPC response fields are populated from incorrect source fields due to copy-and-paste mistakes in the POJO → protobuf conversion layer:

  • NetMetricManager.getNetProtoInfo() assigns UDP inbound traffic to tcpOutTraffic instead of udpInTraffic. As a result, tcpOutTraffic is overwritten with the UDP inbound value, while udpInTraffic is never populated.

  • NodeInfo.transferToProtoEntity() populates needSyncFromPeer from peerInfo.isSyncFlag() instead of peerInfo.isNeedSyncFromPeer().

Both fields are read-only status/statistics data. Neither defect affects node networking, synchronization, or consensus behavior.

Affected API Surface

Both defects occur in the protobuf conversion path and are exposed only through the affected GRPC APIs.

Defect 1 — tcpOutTraffic / udpInTraffic

The defect is in NetMetricManager.getNetProtoInfo() in the framework module and is exposed through GRPC Monitor.GetStatsInfo (Protocol.MetricsInfo).

The HTTP /monitor/getstatsinfo endpoint is not affected. MetricsServlet serializes the POJO populated by NetMetricManager.setNetInfo(), which maps all four traffic directions correctly.

Defect 2 — needSyncFromPeer

The defect is in NodeInfo.transferToProtoEntity() in the common module and is exposed through GRPC Wallet.GetNodeInfo.

The HTTP /wallet/getnodeinfo and /monitor/getnodeinfo endpoints are not affected. GetNodeInfoServlet serializes the POJO directly, and NodeInfoService assigns needSyncFromPeer correctly.

Root Cause

1. NetMetricManager.getNetProtoInfo()

In the UDP block, the target field was not updated after copying the TCP block:

// tcp
RateInfo tcpOutTraffic = net.getTcpOutTraffic();
Protocol.MetricsInfo.RateInfo tcpOUTrafficInfo = tcpOutTraffic.toProtoEntity();
netInfo.setTcpOutTraffic(tcpOUTrafficInfo);
// udp
RateInfo udpInTraffic = net.getUdpInTraffic();
Protocol.MetricsInfo.RateInfo udpInTrafficInfo = udpInTraffic.toProtoEntity();
netInfo.setTcpOutTraffic(udpInTrafficInfo);  // <-- should be setUdpInTraffic

The second assignment overwrites the first one. Consequently, tcpOutTraffic reports the UDP inbound traffic value, while udpInTraffic remains unset and is therefore absent from the response or represented by its default value, depending on the client/output format.

2. NodeInfo.transferToProtoEntity()

isSyncFlag() was copied into the assignment for needSyncFromPeer:

peerInfoBuilder.setSyncFlag(peerInfo.isSyncFlag());
peerInfoBuilder.setHeadBlockTimeWeBothHave(peerInfo.getHeadBlockTimeWeBothHave());
peerInfoBuilder.setNeedSyncFromPeer(peerInfo.isSyncFlag());  // <-- should be isNeedSyncFromPeer()
peerInfoBuilder.setNeedSyncFromUs(peerInfo.isNeedSyncFromUs());

The POJO already carries the correct value: NodeInfoService assigns needSyncFromPeer from PeerConnection.isNeedSyncFromPeer(). The value is therefore lost only during the POJO → protobuf conversion.

For an active peer, syncFlag is normally false, while needSyncFromPeer can independently be true when the local node needs to synchronize from that peer. Because the protobuf conversion uses isSyncFlag() instead of isNeedSyncFromPeer(), the GRPC response fails to expose this state.

Reproduction

Defect 1 — GRPC Monitor.GetStatsInfo

grpcurl -plaintext 127.0.0.1:50051 protocol.Monitor/GetStatsInfo
Compare the result with the HTTP endpoint backed by the same underlying counters:

curl -s http://127.0.0.1:8090/monitor/getstatsinfo
The HTTP endpoint already reports the correct field mapping, making the discrepancy directly observable on the same node.

Illustrative response fragment (values are indicative only):
GRPC GetStatsInfo — before fix

{
  "net": {
    "tcpInTraffic":  { "count": 120000, "meanRate": 1000.0 },
    "tcpOutTraffic": { "count": 3000, "meanRate": 25.0 },
    "udpOutTraffic": { "count": 2800, "meanRate": 23.0 }
  }
}

Here, tcpOutTraffic actually contains the UDP inbound traffic value, while udpInTraffic is not populated.
GRPC GetStatsInfo — after fix

{
  "net": {
    "tcpInTraffic":  { "count": 120000, "meanRate": 1000.0 },
    "tcpOutTraffic": { "count": 98000, "meanRate": 820.0 },
    "udpInTraffic":  { "count": 3000, "meanRate": 25.0 },
    "udpOutTraffic": { "count": 2800, "meanRate": 23.0 }
  }
}

Defect 2 — GRPC Wallet.GetNodeInfo

grpcurl -plaintext -emit-defaults 127.0.0.1:50051 protocol.Wallet/GetNodeInfo

Compare with:

curl -s http://127.0.0.1:8090/wallet/getnodeinfo

For each entry in peerInfoList, the GRPC response currently sets needSyncFromPeer to the same value as syncFlag, while the HTTP response reports the two fields independently.
For example, consider an active peer that the local node currently needs to synchronize from:
GRPC GetNodeInfo — before fix

{
  "syncFlag": false,
  "needSyncFromPeer": false,
  "needSyncFromUs": false
}

GRPC GetNodeInfo — after fix

{
  "syncFlag": false,
  "needSyncFromPeer": true,
  "needSyncFromUs": false
}

In this case, the peer is actively connected and needSyncFromPeer is true. The current GRPC conversion incorrectly reports false because it uses syncFlag as the source field.

Impact

  • Statistics returned by GRPC Monitor.GetStatsInfo and Wallet.GetNodeInfo are inaccurate and may mislead monitoring, capacity planning, and troubleshooting.
  • UDP inbound traffic is not reported through the affected GRPC field, while tcpOutTraffic reports the UDP inbound value instead of the actual TCP outbound traffic.
  • For connected peers, the GRPC needSyncFromPeer field can incorrectly remain false, making the actual per-peer synchronization state unobservable through this API.
  • The same node can report different values over HTTP and GRPC for the same underlying counters/state, which can be confusing for consumers using both APIs.
  • These are read-only reporting defects. Traffic accounting, peer synchronization, and consensus behavior are unaffected because the underlying counters and PeerConnection state are correct.

Backwards Compatibility

The fix changes values returned by two existing GRPC responses. Operators consuming these fields may observe a step change after upgrading:

  • tcpOutTraffic will change from the previously reported UDP inbound value to the actual TCP outbound traffic.
  • udpInTraffic will change from being unset/default to reporting the actual UDP inbound traffic.
  • needSyncFromPeer will stop mirroring syncFlag and will report the actual per-peer synchronization state.

Dashboards or alert rules that rely on historical values of tcpOutTraffic, udpInTraffic, or needSyncFromPeer should be reviewed before upgrading. In particular, consumers that implicitly relied on udpInTraffic being unset or zero may need to update their assumptions.

Consumers using the HTTP endpoints require no changes because those values are already correct.

No protobuf schema change is involved. Protocol.MetricsInfo.NetInfo and Protocol.NodeInfo.PeerInfo already declare all affected fields, so the generated client interfaces remain unchanged and no client recompilation is required.

Suggested Fix

1. Fix the UDP inbound traffic mapping in NetMetricManager.getNetProtoInfo()

- netInfo.setTcpOutTraffic(udpInTrafficInfo);
+ netInfo.setUdpInTraffic(udpInTrafficInfo);

2. Fix the needSyncFromPeer mapping in NodeInfo.transferToProtoEntity()

- peerInfoBuilder.setNeedSyncFromPeer(peerInfo.isSyncFlag());
+ peerInfoBuilder.setNeedSyncFromPeer(peerInfo.isNeedSyncFromPeer());

3. Add unit tests for the POJO → protobuf conversion

Add unit tests that verify each source field is mapped to the corresponding protobuf field.

For the traffic conversion, build a NetInfo object with distinct values for all four traffic directions and assert each target field independently.

For the peer information conversion, use different values for syncFlag and needSyncFromPeer and verify that both values are preserved independently.

Distinct test values are important: tests that use the same value for multiple source fields would not have caught either of these mapping defects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic:apirpc/http related issuetopic:netp2p net work, synchronization

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions