Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
72816cc
Add Http2ClientProtocolConfig to block-nodes json
derektriley Oct 22, 2025
1499a8e
Add GrpcClientProtocolConfig to block-nodes json
derektriley Oct 22, 2025
876ae4e
unit tests
derektriley Oct 22, 2025
6a2a22d
javadoc
derektriley Oct 22, 2025
f8552a9
clear grpc configs
derektriley Oct 22, 2025
34cdc3c
types
derektriley Oct 22, 2025
23d876e
finals
derektriley Oct 22, 2025
e8aea24
Merge remote-tracking branch 'remotes/origin/main' into 21777-http2cl…
derektriley Oct 24, 2025
333cc5e
wip maxMessageSizeBytes
derektriley Oct 24, 2025
4082270
unit tests
derektriley Oct 24, 2025
938f016
javadoc
derektriley Oct 24, 2025
53248c9
Merge remote-tracking branch 'remotes/origin/main' into 21777-http2cl…
derektriley Oct 29, 2025
d6b6b36
wip
derektriley Oct 29, 2025
a60f194
unit tests
derektriley Oct 29, 2025
edf6e63
markdown
derektriley Oct 29, 2025
7917bd1
Update Unit Tests and rename
derektriley Nov 4, 2025
ccbc71b
Merge remote-tracking branch 'remotes/origin/main' into 21777-http2cl…
derektriley Nov 4, 2025
0d306c3
fix unit test
derektriley Nov 4, 2025
77cc406
Merge remote-tracking branch 'remotes/origin/main' into 21777-http2cl…
derektriley Nov 4, 2025
388f561
Merge remote-tracking branch 'remotes/origin/main' into 21777-http2cl…
derektriley Nov 4, 2025
ac9b7c8
updates
derektriley Nov 4, 2025
63d1ddd
chore: updated 21777 with main (#22123)
AlexKehayov Nov 12, 2025
f6803a1
Revert "chore: updated 21777 with main (#22123)"
derektriley Nov 13, 2025
d73a237
chore: Rebased 21777 on main (#22150)
AlexKehayov Nov 13, 2025
4d393bf
sign
petreze Nov 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions hapi/hapi/src/main/proto/network/block_node_connections.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ option java_package = "com.hedera.node.internal.network.legacy";
// <<<pbj.java_package = "com.hedera.node.internal.network">>> This comment is special code for setting PBJ Compiler java package
option java_multiple_files = true;

import "google/protobuf/wrappers.proto";

/**
* A single block node connection configuration.<br/>
*
Expand Down Expand Up @@ -57,6 +59,106 @@ message BlockNodeConfig {
* node SHALL connect to a node in the next-highest available priority group.
*/
int32 priority = 3;

/**
* Optional HTTP/2 client protocol configuration for this block node connection.
* If present, these settings SHALL override defaults when creating the WebClient.
*/
Http2ClientProtocolConfig http2ClientProtocolConfig = 4;

/**
* Optional Grpc client protocol configuration for this block node connection.
* If present, these settings SHALL override defaults when creating the WebClient.
*/
GrpcClientProtocolConfig grpcClientProtocolConfig = 5;

/**
* Optional maximum message size in bytes that the client will send to the block node.
* If present, this value SHALL override the default maximum message size.
*/
google.protobuf.UInt32Value maxMessageSizeBytes = 6;
}


/**
* Optional HTTP/2 client protocol configuration for a specific block node connection.
* If present, these values SHALL be used to configure the HTTP/2 protocol for the WebClient connecting
* to the corresponding block node.
*/
message Http2ClientProtocolConfig {
/**
* Timeout for blocking while waiting for window update when window is depleted.
* ISO-8601 duration string (e.g., "PT15S").
*/
google.protobuf.StringValue flow_control_block_timeout = 1;

/**
* Configure INITIAL_WINDOW_SIZE setting for new HTTP/2 connections.
*/
google.protobuf.Int32Value initial_window_size = 2;

/**
* Configure initial MAX_FRAME_SIZE setting for new HTTP/2 connections.
*/
google.protobuf.Int32Value max_frame_size = 3;

/**
* Configure initial MAX_HEADER_LIST_SIZE setting for new HTTP/2 connections.
*/
google.protobuf.Int64Value max_header_list_size = 4;

/**
* Name of this HTTP/2 protocol configuration. Default is "h2".
*/
google.protobuf.StringValue name = 5;

/**
* Check healthiness of cached connections with HTTP/2.0 ping frame.
*/
google.protobuf.BoolValue ping = 6;

/**
* Timeout for ping probe used for checking healthiness of cached connections.
* ISO-8601 duration string (e.g., "PT0.5S").
*/
google.protobuf.StringValue ping_timeout = 7;

/**
* Prior knowledge of HTTP/2 capabilities of the server.
*/
google.protobuf.BoolValue prior_knowledge = 8;
}

message GrpcClientProtocolConfig {
/**
* Whether to continue retrying after a poll wait timeout expired or not. If a read operation timeouts out and this
* flag is set to false, the event is logged and the client will retry. Otherwise, an exception is thrown.
*/
google.protobuf.BoolValue abort_poll_time_expired = 1;

/**
* How often to send a heartbeat (HTTP/2 ping) to check if the connection is still alive. This is useful for
* long-running, streaming gRPC calls. It is turned off by default but can be enabled by setting the period to a value
* greater than 0. ISO-8601 duration string (e.g., "PT0S").
*/
google.protobuf.StringValue heartbeat_period = 2;

/**
* Initial buffer size used to serialize gRPC request payloads. Buffers shall grow according to the payload size, but
* setting this initial buffer size to a larger value may improve performance for certain applications.
*/
google.protobuf.Int32Value init_buffer_size = 3;

/**
* Name identifying this client protocol. Defaults to type.
*/
google.protobuf.StringValue name = 4;

/**
* How long to wait for the next HTTP/2 data frame to arrive in underlying stream. Whether this is a fatal error or
* not is controlled by abort_poll_time_expired(). ISO-8601 duration string (e.g., "PT10S").
*/
google.protobuf.StringValue poll_wait_time = 5;
}

/**
Expand Down
1 change: 1 addition & 0 deletions hedera-node/docs/design/app/blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class or component and its role, including interactions with other components.
| [BlockNodeConnection.md](BlockNodeConnection.md) | BlockNodeConnection | Internal design and behavior of the BlockNodeConnection class, representing an individual connection. |
| [BlockState.md](BlockState.md) | BlockState | Internal design of the BlockState component, managing state information for blocks. |
| [BlockBufferService.md](BlockBufferService.md) | BlockBufferService | Internal design and responsibilities of BlockBufferService, handling stream state and synchronization. |
| [block-nodes-json.md](block-nodes-json.md) | Configuration | JSON structure and options for `block-nodes.json`, protocol overrides, and live reload behavior. |

## Components Interaction Flow

Expand Down
102 changes: 102 additions & 0 deletions hedera-node/docs/design/app/blocks/block-nodes-json.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
## Block Nodes JSON configuration

This document describes the `block-nodes.json` file used to configure which Block Nodes a Consensus Node can connect to, along with optional client protocol settings per node.

Note: The canonical definition of this structure is the HAPI proto located at `hapi/hapi/src/main/proto/network/block_node_connections.proto`. The `block-nodes.json` file uses the PBJ JSON encoding of that schema.

The file is read from the directory configured by `blockNode.blockNodeConnectionFileDir` and must be named `block-nodes.json`.

### Top-level structure

The file is a JSON object with a single field:

- `nodes`: array of Block Node entries

### Node entry schema

Each element of `nodes` has the following fields:

- `address` (string, required): Hostname or IPv4/IPv6 address of the Block Node (e.g. `"localhost"`, `"10.0.0.5"`).
- `port` (integer, required): TCP port for the node’s gRPC endpoint.
- `priority` (integer, required): Lower numbers are higher priority. Nodes with smaller priority values are preferred for selection. Among nodes with the same priority, selection is randomized.
- `http2ClientProtocolConfig` (object, optional): Overrides for the HTTP/2 client.
- `name` (string, optional)
- `ping` (boolean, optional)
- `pingTimeout` (string, optional): ISO-8601 duration, e.g. `"PT0.5S"` for 500ms.
- `flowControlBlockTimeout` (string, optional): ISO-8601 duration.
- `initialWindowSize` (integer, optional)
- `maxFrameSize` (integer, optional)
- `maxHeaderListSize` (string, optional): may be `"-1"` to indicate unlimited (as supported by Helidon config).
- `priorKnowledge` (boolean, optional)
- `grpcClientProtocolConfig` (object, optional): Overrides for the gRPC protocol.
- `name` (string, optional)
- `abortPollTimeExpired` (boolean, optional)
- `heartbeatPeriod` (string, optional): ISO-8601 duration, e.g. `"PT10S"`.
- `initBufferSize` (integer, optional)
- `pollWaitTime` (string, optional): ISO-8601 duration.
- `maxMessageSizeBytes` (integer, optional): Maximum per-request payload size in bytes for this node. The system enforces an upper cap of 2,097,152 bytes (2 MB) due to PBJ limits; if configured above this, the effective limit will be 2 MB.

### Example

```json
{
"nodes": [
{
"address": "localhost",
"port": 50051,
"priority": 0,
"http2ClientProtocolConfig": {
"name": "h2",
"ping": true,
"pingTimeout": "PT0.5S",
"flowControlBlockTimeout": "PT1S",
"initialWindowSize": 12345,
"maxFrameSize": 16384,
"maxHeaderListSize": "-1",
"priorKnowledge": false
},
"grpcClientProtocolConfig": {
"name": "grpc",
"abortPollTimeExpired": false,
"heartbeatPeriod": "PT0S",
"initBufferSize": 1024,
"pollWaitTime": "PT10S"
},
"maxMessageSizeBytes": 1500000
},
{
"address": "pbj-unit-test-host",
"port": 8081,
"priority": 1
}
]
}
```

### Selection behavior

- Nodes are grouped by `priority` and considered from lowest value to highest.
- Within a priority group, selection is randomized among nodes that are not already connected.
- If multiple nodes are configured, the manager can switch to the next available node when latency limits or other criteria indicate it should.

### Defaults and missing values

- If `http2ClientProtocolConfig` or `grpcClientProtocolConfig` are omitted, sensible defaults are used by the client.
- If `maxMessageSizeBytes` is omitted, the effective per-request limit defaults to 2,097,152 bytes (2 MB).

### Live reload behavior

- The `block-nodes.json` file is watched for create/modify/delete events.
- On change, the manager reloads the file, shuts down any existing connections, and restarts with the new nodes.
- If the contents are unchanged, no restart is performed.
- If the file is missing or the contents fail to parse, the manager logs the issue and will not establish block node connections until a valid file is present again.

### Validation notes

- Durations must be valid ISO-8601 strings (e.g. `"PT30S"`, `"PT1M"`). Invalid duration strings are ignored with a warning, and defaults apply for those fields.
- `priority` should be a non-negative integer. Use `0` for the highest priority.
- `address` must be resolvable by the OS DNS stack or be a valid IP address. If resolution fails, the active-connection-IP metric will report `-1` for that node.

### Related configuration (outside this file)

While the JSON file declares the set of nodes and per-node protocol overrides, general streaming behavior is configured via the `blockNode` section in the application configuration (e.g. `blockNode.blockNodeConnectionFileDir`, backoff limits, latency thresholds, etc.).
1 change: 1 addition & 0 deletions hedera-node/hedera-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mainModuleInfo {
runtimeOnly("io.helidon.grpc.core")
runtimeOnly("io.helidon.webclient")
runtimeOnly("io.helidon.webclient.grpc")
runtimeOnly("io.helidon.webclient.http2")
runtimeOnly("com.hedera.pbj.grpc.client.helidon")
runtimeOnly("com.hedera.pbj.grpc.helidon")
}
Expand Down
Loading