Skip to content

Commit 0c3b0fe

Browse files
committed
Merge branch 'main' into 642-chore-improvements-for-test-repeatability
Signed-off-by: Alex Kehayov <[email protected]>
2 parents 35d4219 + ab846e5 commit 0c3b0fe

File tree

26 files changed

+353
-660
lines changed

26 files changed

+353
-660
lines changed

.github/workflows/pr-checks.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ jobs:
6767
java-version: "21.0.6"
6868

6969
- name: Cache Gradle packages
70-
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
70+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
7171
with:
7272
path: |
7373
~/.gradle/caches

.github/workflows/smoke-test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
rm grpcurl.tar.gz
5656
5757
- name: Cache Gradle packages
58-
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
58+
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
5959
with:
6060
path: |
6161
~/.gradle/caches

charts/block-node-server/dashboards/block-node-server.json

Lines changed: 46 additions & 46 deletions
Large diffs are not rendered by default.

charts/block-node-server/values.yaml

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ ingress:
5858

5959
resources:
6060
requests:
61-
cpu: "2"
62-
memory: "8Gi"
61+
cpu: "8"
62+
memory: "24Gi"
6363

6464
nodeSelector: {}
6565

@@ -73,8 +73,14 @@ blockNode:
7373
config:
7474
# Add any additional env configuration here
7575
# key: value
76-
BLOCKNODE_STORAGE_ROOT_PATH: "/app/storage"
7776
JAVA_TOOL_OPTIONS: "-Djava.util.logging.config.file=/app/logs/config/logging.properties"
77+
JAVA_OPTS: "-Xms16G -Xmx16G"
78+
# PRODUCER_TYPE: "NO_OP"
79+
# PERSISTENCE_STORAGE_TYPE: "NO_OP"
80+
# VERIFICATION_TYPE: "NO_OP"
81+
# MEDIATOR_TYPE: "NO_OP"
82+
MEDIATOR_RING_BUFFER_SIZE: "4096"
83+
7884
secret:
7985
PRIVATE_KEY: "fake_private_key"
8086
health:
@@ -84,18 +90,12 @@ blockNode:
8490
endpoint: "/healthz/livez"
8591
metrics:
8692
port: 9999
87-
resources:
88-
limits:
89-
cpu: "8"
90-
memory: "16Gi"
91-
requests:
92-
cpu: "2"
93-
memory: "8Gi"
9493
logs:
9594
# Available Levels are (from most verbose to least verbose):
9695
# ALL FINEST FINER FINE CONFIG INFO WARNING SEVERE OFF
9796
level: "INFO"
9897
loggingProperties:
98+
# com.hedera.block.server.producer.ProducerBlockItemObserver.level: "FINE"
9999
io.helidon.webserver.level: "INFO"
100100
io.helidon.webserver.access.level: "INFO"
101101
io.helidon.config.level: "SEVERE"
@@ -121,10 +121,7 @@ blockNode:
121121
# %4$ - log level
122122
# %5$ - log message
123123
# %6$ - throwable trace
124-
#
125-
# Example to produce a line such as:
126-
# 2025-01-04 00:34:43 INFO [com.hedera.block.server.Server main] Starting BlockNode Server
127-
java.util.logging.SimpleFormatter.format: "%1$tF %1$tT %4$-7s [%2$s] %5$s %n"
124+
java.util.logging.SimpleFormatter.format: "%TF %<TT.%<TL%<Tz %4$-7s [%2$s] %5$s%6$s%n"
128125

129126
kubepromstack:
130127
enabled: true

charts/blockstream-simulator/templates/deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ metadata:
99
labels:
1010
{{- include "blockstream-simulator-chart.labels" . | nindent 4 }}
1111
spec:
12-
replicas: 1
12+
replicas: {{ .Values.replicas }}
1313
selector:
1414
matchLabels:
1515
{{- include "blockstream-simulator-chart.selectorLabels" . | nindent 6 }}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# 2 consumers
2+
replicas: 2
3+
4+
simulator:
5+
config:
6+
GRPC_SERVER_ADDRESS: "my-bn-block-node-helm-chart"
7+
BLOCK_STREAM_SIMULATOR_MODE: "CONSUMER"

charts/blockstream-simulator/values.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,17 @@ nodeSelector: {}
1616
tolerations: []
1717
affinity: {}
1818

19+
replicas: 1
20+
1921
simulator:
2022
config:
2123
# either CONSUMER or PUBLISHER
22-
BLOCK_STREAM_SIMULATOR_MODE: "PUBLISHER"
23-
GRPC_SERVER_ADDRESS: "bn-release-block-node-helm-chart"
24+
BLOCK_STREAM_SIMULATOR_MODE: "PUBLISHER_CLIENT"
25+
GRPC_SERVER_ADDRESS: "my-bn-block-node-helm-chart"
26+
# GENERATOR_START_BLOCK_NUMBER: 0
27+
# GENERATOR_MIN_TRANSACTIONS_PER_EVENT: 500
28+
# GENERATOR_MAX_TRANSACTIONS_PER_EVENT: 5000
29+
# BLOCK_STREAM_BLOCK_ITEMS_BATCH_SIZE: 250
30+
# BLOCK_STREAM_MILLISECONDS_PER_BLOCK: 1000
2431
secret:
2532
PRIVATE_KEY: "fake_private_key"

docs/design/Nano-Service-Approach.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Block Node Nano-Service Approach
2+
3+
## Abstract
4+
5+
To date, block node has been developed under pressure and with changing, incomplete, or inaccurate requirements.
6+
As a result, the system is tightly interconnected, and suffers from a difficulty making changes to
7+
one segment of the system without also impacting unrelated segments. To address this, and ensure
8+
the Block Node is able to be extended, enhanced, and deployed in the manner required for all
9+
current identified usage, a modified structure of the system is herein detailed.
10+
11+
## Revised Diagram
12+
13+
![Module/Service Diagram](assets/Block-Node-Nano-Services.svg)
14+
15+
## Definitions
16+
17+
<dl>
18+
<dt>Event</dt>
19+
<dd>A Java object defined by the messaging service that enables each other service
20+
to publish a service-defined object with content specific to that service. Note,
21+
the name of this object is not defined in this document. "Event" is a generic term.</dd>
22+
<dt>Service</dt>
23+
<dd>A Java module that is deployed with a particular installation of the Hiero
24+
Block Node. In most cases these modules are housed in independent jars to make
25+
adding and removing services (in a custom deployment) easier.</dd>
26+
</dl>
27+
28+
## Core Concepts
29+
30+
1. Helidon and API objects are restricted to the API layer.
31+
* The less we flow these externally defined interfaces and classes through
32+
the system, the more easily we can potentially make outward facing API
33+
changes without reworking the internal design.
34+
2. Most services are not required to be present in every deployment of the block node.
35+
3. No service should depend on classes or interfaces from another service.
36+
* That service might not be deployed, and each service should be removable
37+
without breaking other services. The exception is the Messaging service.
38+
* To this end, services should be independent modules with clearly defined
39+
and carefully controlled interactions.
40+
4. Two services are required for all deployments, Messaging and Status
41+
* Only Messaging should offer any internal API at all.
42+
* Basically, Messaging is where data and events are published (presumably
43+
via LMAX Disruptor instances) among other services.
44+
* The Status service is only required because it is specified as always
45+
present for a block node client to query via gRPC API.
46+
* The Messaging service should _not_ have any external (i.e. gRPC) API.
47+
* We must remain vigilant to avoid packing these two services with interfaces or extra classes.
48+
* These services should be as slim as possible, and interactions between
49+
services should be based on a very limited set of `Record` messages ("Events")
50+
that are passed between services (blindly) by the Messaging service
51+
rather than interfaces or direct method calls.
52+
5. There is an assumption in this approach that Messaging offers both "push"
53+
and "pull" options for receiving messages, and each service may choose the
54+
most appropriate interaction for that specific service.
55+
* A persistence service, for instance, might use "push" for simplicity and
56+
because it does not benefit from holding items within Messaging, but
57+
a streaming client service might use "pull" in order to allow each of
58+
many remote clients to be receiving data at slightly varying rates and
59+
more easily switch from live to historical and back if a particular
60+
client falls behind and later "catches up".
61+
6. Most services both publish and observe the service "event" messages
62+
* By listening for events, any service can react to changes in any other
63+
service, but also behave reasonably when another service does not exist.
64+
* Publishing an event (rather than calling an API) makes it easy for each
65+
service to focus entirely on its own function and not try to work out the
66+
highly complex possible interactions with all other possible services.
67+
* Some services (e.g. Archive service) won't make sense if _nothing_ publishes
68+
a particular event, but even then the service need not be concerned with
69+
the how/what/why of a event, and need only react if and when a event is
70+
encountered with the relevant type and content.
71+
7. Many services will _also_ listen to the main data messages (List<BlockItem>)
72+
which is the primary data flowing through the system.
73+
* Note that Publisher service is also not required, so this flow of data might
74+
be empty, or might be produced from some other source.
75+
* There _might_ also be a stream of "historical" blocks used to serve client
76+
requests for those blocks. This is still to be determined.
77+
8. Configuration for a service is entirely restricted to that service, and does
78+
not determine what "version" of a service or whether a service is running.
79+
* It _might_ assist multiple loaded "versions" to identify a conflict.
80+
9. The JVM `ServiceLoader` is used to load every service that is present, this
81+
may include multiple services of the same "type" (e.g. multiple archive
82+
services, multiple persistence services, etc...).
83+
* It is up to the particular services to ensure that either multiple
84+
different versions cooperate properly or an error is published on
85+
startup that multiple incompatible services are loaded. Generally it's
86+
cleanest if multiple services of the same type are able to work
87+
independently without issues. If that isn't possible, a service-
88+
specific configuration is a good alternative.
89+
90+
## Expected Benefits
91+
92+
1. Services are decomposed to small units, often what is thought of as a single
93+
process is accomplished by multiple nano-services. This makes each such
94+
service both simple and focused. This also makes adding, removing, and
95+
modifying these services much easier and faster.
96+
* It's also much easier to test services with nothing more than a mock of the
97+
"Messaging" service; which further improves velocity.
98+
2. Composing services may be easier to reason about than composing interfaces,
99+
and systems composed of independent services are easier to modify and revise
100+
than systems with many interacting method calls or complex module
101+
interactions.
102+
3. It is much easier to reason about concurrency for a single focused service
103+
than it is for a larger and more interconnected set of components.
104+
105+
## Considerations and Possible Concerns
106+
107+
1. Sending messages between services is not as efficient as calling a method.
108+
* This is true, but publishing a message consumed by an unknown set of (potentially)
109+
several services is significantly more efficient than trying to manage an uncertain
110+
(and possibly large) number of direct method calls. We are electing to
111+
prioritize emergent behavior and capability over direct-call efficiency.
112+
2. Some services may not make any sense without other services. For example,
113+
a Content Proof service might not be able to function without a State
114+
Management service and/or State Snapshot service.
115+
* If a particular service requires other services, it should document the
116+
expected events (e.g. publish "Need Snapshot For Instant{date/time}" and
117+
expect "Deliver Snapshot For Instant{date1/time1}") and also document
118+
behavior if the response-type event is not published.
119+
* Every service should function, at least to the level of not throwing
120+
exceptions, regardless of which other services are, or are not, present.
121+
* While a service may require certain _messages_ to function correctly
122+
(e.g. a "Deliver Snapshot For Instant..." message in the example above),
123+
the service _must not_ concern itself with _what_ produces those messages
124+
or _how_. This ensures that all services function as intended even if
125+
other services are replaced with completely different, but _compatible_
126+
services.

docs/design/assets/Block-Node-Nano-Services.svg

Lines changed: 1 addition & 0 deletions
Loading

hiero-dependency-versions/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ dependencies.constraints {
1414
val helidonVersion = "4.1.6"
1515
val pbjVersion = "0.9.17"
1616
val protobufVersion = "4.29.3"
17-
val swirldsVersion = "0.58.4"
17+
val swirldsVersion = "0.59.2"
1818

1919
api("com.github.luben:zstd-jni:1.5.7-1") { because("com.github.luben.zstd_jni") }
20-
api("com.github.spotbugs:spotbugs-annotations:4.9.1") {
20+
api("com.github.spotbugs:spotbugs-annotations:4.9.2") {
2121
because("com.github.spotbugs.annotations")
2222
}
2323
api("com.google.auto.service:auto-service-annotations:1.1.1") {
@@ -70,7 +70,7 @@ dependencies.constraints {
7070
api("org.mockito:mockito-core:5.15.2") { because("org.mockito") }
7171
api("org.mockito:mockito-junit-jupiter:5.15.2") { because("org.mockito.junit.jupiter") }
7272
api("org.testcontainers:junit-jupiter:1.20.5") { because("org.testcontainers.junit.jupiter") }
73-
api("org.testcontainers:testcontainers:1.20.4") { because("org.testcontainers") }
73+
api("org.testcontainers:testcontainers:1.20.5") { because("org.testcontainers") }
7474

7575
api("com.google.auto.service:auto-service:1.1.1") {
7676
because("com.google.auto.service.processor")

0 commit comments

Comments
 (0)