├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── 01-Story-Template.yml │ ├── 02-Epic-Template.yml │ ├── 03-Bug-Template.yml │ └── config.yml ├── dependabot.yml ├── pull_request_template.md ├── release.yaml └── workflows │ ├── e2e-tests.yaml │ ├── helm-charts.yaml │ ├── local-node-test-reusable.yaml │ ├── local-node-test.yaml │ ├── pr-checks.yaml │ ├── pr-formatting.yaml │ ├── release-automation.yaml │ ├── release-push-image.yaml │ ├── support │ └── scripts │ │ └── generate-gradle-artifact-baseline.sh │ └── zxc-verify-gradle-build-determinism.yaml ├── .gitignore ├── .idea └── .gitignore ├── .markdownlint.yaml ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── SECURITY.md ├── block-node ├── README.md ├── app │ ├── build.gradle.kts │ ├── docker │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── docker-build.sh │ │ ├── docker-compose.yml │ │ ├── logging.properties │ │ ├── loki-config.yaml │ │ ├── metrics │ │ │ ├── dashboards │ │ │ │ ├── Hiero-Block-Node-Plugins │ │ │ │ │ ├── app-core.json │ │ │ │ │ ├── block-access-service.json │ │ │ │ │ ├── block-node-service.json │ │ │ │ │ ├── block-provider-files-historic.json │ │ │ │ │ ├── block-provider-files-recent.json │ │ │ │ │ ├── messaging-facility.json │ │ │ │ │ ├── stream-publisher.json │ │ │ │ │ ├── stream-subscriber.json │ │ │ │ │ └── verification.json │ │ │ │ ├── block-node-server-logs.json │ │ │ │ ├── block-node-server.json │ │ │ │ ├── block-stream-simulator-consumer.json │ │ │ │ ├── block-stream-simulator-publisher.json │ │ │ │ ├── cAdvisor.json │ │ │ │ └── provisioner.yaml │ │ │ ├── datasources │ │ │ │ └── datasources.yml │ │ │ └── prometheus.yml │ │ ├── promtail-config.yaml │ │ ├── repro-sources-list.sh │ │ └── update-env.sh │ └── src │ │ ├── main │ │ ├── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ │ └── hiero │ │ │ │ └── block │ │ │ │ └── node │ │ │ │ └── app │ │ │ │ ├── BlockNodeApp.java │ │ │ │ ├── DefaultThreadPoolManager.java │ │ │ │ ├── HistoricalBlockFacilityImpl.java │ │ │ │ ├── ServerConfig.java │ │ │ │ ├── ServiceBuilderImpl.java │ │ │ │ ├── config │ │ │ │ ├── AutomaticEnvironmentVariableConfigSource.java │ │ │ │ └── ConfigLogger.java │ │ │ │ └── logging │ │ │ │ └── CleanColorfulFormatter.java │ │ └── resources │ │ │ ├── app.properties │ │ │ └── logging.properties │ │ ├── test │ │ ├── java │ │ │ └── org │ │ │ │ └── hiero │ │ │ │ └── block │ │ │ │ └── node │ │ │ │ └── app │ │ │ │ ├── BlockNodeAppTest.java │ │ │ │ ├── DefaultThreadPoolManagerTest.java │ │ │ │ ├── HistoricalBlockFacilityImplTest.java │ │ │ │ ├── ServerConfigTest.java │ │ │ │ ├── ServiceBuilderImplTest.java │ │ │ │ ├── config │ │ │ │ ├── AutomaticEnvironmentVariableConfigSourceTest.java │ │ │ │ ├── ConfigLoggerImplTest.java │ │ │ │ └── TestSecretConfig.java │ │ │ │ └── logging │ │ │ │ └── CleanColorfulFormatterTest.java │ │ ├── network-latency-simulator │ │ │ ├── .gitignore │ │ │ ├── Dockerfile │ │ │ ├── README.md │ │ │ ├── configure_latency.sh │ │ │ ├── setup.sh │ │ │ └── start.sh │ │ └── resources │ │ │ └── app-test.properties │ │ └── testFixtures │ │ ├── java │ │ ├── module-info.java │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── app │ │ │ └── fixtures │ │ │ ├── TestUtils.java │ │ │ ├── async │ │ │ ├── BlockingSerialExecutor.java │ │ │ └── TestThreadPoolManager.java │ │ │ ├── blocks │ │ │ ├── BlockItemUtils.java │ │ │ ├── BlockUtils.java │ │ │ ├── InMemoryBlockAccessor.java │ │ │ └── SimpleTestBlockItemBuilder.java │ │ │ ├── logging │ │ │ └── CleanColorfulFormatter.java │ │ │ └── plugintest │ │ │ ├── GrpcPluginTestBase.java │ │ │ ├── NoBlocksHistoricalBlockFacility.java │ │ │ ├── NoOpServiceBuilder.java │ │ │ ├── PluginTestBase.java │ │ │ ├── SimpleBlockRangeSet.java │ │ │ ├── SimpleInMemoryHistoricalBlockFacility.java │ │ │ ├── TestBlockMessagingFacility.java │ │ │ └── TestHealthFacility.java │ │ └── resources │ │ └── test-blocks │ │ └── generated-10.blk.gz ├── base │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── base │ │ │ ├── BlockFile.java │ │ │ ├── CompressionType.java │ │ │ ├── Loggable.java │ │ │ ├── ranges │ │ │ ├── CombinedBlockRangeSet.java │ │ │ └── ConcurrentLongRangeSet.java │ │ │ ├── s3 │ │ │ ├── S3Client.java │ │ │ ├── S3ClientException.java │ │ │ ├── S3ClientInitializationException.java │ │ │ └── S3ResponseException.java │ │ │ └── tar │ │ │ └── TaredBlockIterator.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── base │ │ ├── BlockFileTest.java │ │ ├── CompressionTypeTest.java │ │ ├── ranges │ │ ├── CombinedBlockRangeSetTest.java │ │ ├── ConcurrentLongRangeSetTest.java │ │ └── ConcurrentLongRangeSetThreadingTest.java │ │ ├── s3 │ │ └── S3ClientTest.java │ │ └── tar │ │ └── TaredBlockIteratorTest.java ├── block-access │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── access │ │ │ └── service │ │ │ └── BlockAccessServicePlugin.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── access │ │ └── service │ │ └── BlockAccessServicePluginTest.java ├── block-providers │ ├── files.historic │ │ ├── build.gradle.kts │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ ├── module-info.java │ │ │ │ └── org │ │ │ │ └── hiero │ │ │ │ └── block │ │ │ │ └── node │ │ │ │ └── blocks │ │ │ │ └── files │ │ │ │ └── historic │ │ │ │ ├── BlockPath.java │ │ │ │ ├── BlocksFilesHistoricPlugin.java │ │ │ │ ├── FilesHistoricConfig.java │ │ │ │ ├── ZipBlockAccessor.java │ │ │ │ └── ZipBlockArchive.java │ │ │ └── test │ │ │ └── java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── blocks │ │ │ └── files │ │ │ └── historic │ │ │ ├── BlockPathTest.java │ │ │ ├── BlocksFilesHistoricPluginTest.java │ │ │ ├── FilesHistoricConfigTest.java │ │ │ ├── ZipBlockAccessorTest.java │ │ │ └── ZipBlockArchiveTest.java │ └── files.recent │ │ ├── build.gradle.kts │ │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── blocks │ │ │ └── files │ │ │ └── recent │ │ │ ├── BlockFileBlockAccessor.java │ │ │ ├── BlocksFilesRecentPlugin.java │ │ │ └── FilesRecentConfig.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── blocks │ │ └── files │ │ └── recent │ │ ├── BlockFileBlockAccessorTest.java │ │ ├── BlockFileRecentPluginTest.java │ │ └── FilesRecentConfigTest.java ├── health │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── health │ │ │ └── HealthServicePlugin.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── health │ │ └── HealthServiceTest.java ├── messaging │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── messaging │ │ │ ├── BlockItemBatchRingEvent.java │ │ │ ├── BlockMessagingFacilityImpl.java │ │ │ ├── BlockNotificationRingEvent.java │ │ │ └── MessagingConfig.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── server │ │ └── messaging │ │ ├── BlockItemBatchRingEventTest.java │ │ ├── BlockMessagingFacilityExceptionTest.java │ │ ├── BlockMessagingServiceBlockItemTest.java │ │ ├── BlockMessagingServiceBlockNotificationTest.java │ │ ├── BlockMessagingServiceDynamicBlockItemTest.java │ │ ├── BlockNotificationRingEventTest.java │ │ ├── MessagingConfigTest.java │ │ └── TestConfig.java ├── protobuf-pbj │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── module-info.java ├── s3-archive │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── archive │ │ │ └── s3 │ │ │ ├── S3ArchiveConfig.java │ │ │ └── S3ArchivePlugin.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── archive │ │ └── s3 │ │ └── S3ArchivePluginTest.java ├── server-status │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── server │ │ │ └── status │ │ │ └── ServerStatusServicePlugin.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── server │ │ └── status │ │ └── ServerStatusServicePluginTest.java ├── spi │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── spi │ │ │ ├── BlockNodeContext.java │ │ │ ├── BlockNodePlugin.java │ │ │ ├── ServiceBuilder.java │ │ │ ├── ServiceLoaderFunction.java │ │ │ ├── blockmessaging │ │ │ ├── BlockItemHandler.java │ │ │ ├── BlockItems.java │ │ │ ├── BlockMessagingFacility.java │ │ │ ├── BlockNotificationHandler.java │ │ │ ├── NoBackPressureBlockItemHandler.java │ │ │ ├── PersistedNotification.java │ │ │ └── VerificationNotification.java │ │ │ ├── health │ │ │ └── HealthFacility.java │ │ │ ├── historicalblocks │ │ │ ├── BlockAccessor.java │ │ │ ├── BlockProviderPlugin.java │ │ │ ├── BlockRangeSet.java │ │ │ ├── HistoricalBlockFacility.java │ │ │ └── LongRange.java │ │ │ └── threading │ │ │ └── ThreadPoolManager.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── spi │ │ ├── BlockNodePluginTest.java │ │ ├── blockmessaging │ │ └── BlockItemsTest.java │ │ ├── health │ │ └── HealthFacilityTest.java │ │ └── historicalblocks │ │ ├── BlockAccessorTest.java │ │ ├── BlockRangeSetTest.java │ │ └── LongRangeTest.java ├── stream-publisher │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── stream │ │ │ └── publisher │ │ │ ├── BlockStreamProducerSession.java │ │ │ ├── PublisherConfig.java │ │ │ ├── PublisherServicePlugin.java │ │ │ └── UpdateCallback.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── stream │ │ └── publisher │ │ ├── BlockStreamProducerSessionTest.java │ │ ├── PublisherConfigTest.java │ │ └── PublisherTest.java ├── stream-subscriber │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── node │ │ │ └── stream │ │ │ └── subscriber │ │ │ ├── BlockStreamSubscriberSession.java │ │ │ ├── SubscriberConfig.java │ │ │ └── SubscriberServicePlugin.java │ │ └── test │ │ └── java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── stream │ │ └── subscriber │ │ ├── BlockStreamSubscriberSessionTest.java │ │ ├── SubscriberConfigTest.java │ │ └── SubscriberTest.java └── verification │ ├── build.gradle.kts │ └── src │ ├── main │ └── java │ │ ├── module-info.java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── node │ │ └── verification │ │ ├── BlockVerificationSession.java │ │ ├── VerificationConfig.java │ │ └── VerificationServicePlugin.java │ └── test │ └── java │ └── org │ └── hiero │ └── block │ └── node │ └── verification │ ├── BlockVerificationSessionTest.java │ └── VerificationServicePluginTest.java ├── build.gradle.kts ├── charts ├── .gitignore ├── block-node-server │ ├── .helmignore │ ├── Chart.yaml │ ├── README.md │ ├── dashboards │ │ ├── Hiero-Block-Node-Plugins │ │ │ ├── app-core.json │ │ │ ├── block-access-service.json │ │ │ ├── block-node-service.json │ │ │ ├── block-provider-files-historic.json │ │ │ ├── block-provider-files-recent.json │ │ │ ├── messaging-facility.json │ │ │ ├── stream-publisher.json │ │ │ ├── stream-subscriber.json │ │ │ └── verification.json │ │ ├── block-node-server.json │ │ ├── kubernetes-views-pods.json │ │ └── node-exporter-full.json │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── configmap-logging.yaml │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── grafana-dashboard-configmap.yaml │ │ ├── grafana-datasource.yaml │ │ ├── ingress.yaml │ │ ├── pvc-archive.yaml │ │ ├── pvc-live.yaml │ │ ├── pvc-logging.yaml │ │ ├── secret.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── servicemonitor.yaml │ ├── values-overrides │ │ ├── mid-size.yaml │ │ └── mini.yaml │ └── values.yaml └── blockstream-simulator │ ├── .helmignore │ ├── Chart.yaml │ ├── README.md │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── configmap.yaml │ ├── deployment.yaml │ ├── pvc-simulator-data.yaml │ └── secret.yaml │ ├── values-overrides │ └── consumer.yaml │ └── values.yaml ├── codecov.yml ├── common ├── build.gradle.kts └── src │ ├── main │ └── java │ │ ├── module-info.java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── common │ │ ├── constants │ │ └── StringsConstants.java │ │ ├── hasher │ │ ├── ConcurrentStreamingTreeHasher.java │ │ ├── Hashes.java │ │ ├── HashingUtilities.java │ │ ├── NaiveStreamingTreeHasher.java │ │ └── StreamingTreeHasher.java │ │ └── utils │ │ ├── ChunkUtils.java │ │ ├── FileUtilities.java │ │ ├── MathUtilities.java │ │ ├── Preconditions.java │ │ └── StringUtilities.java │ └── test │ ├── java │ └── org │ │ └── hiero │ │ └── block │ │ └── common │ │ ├── CommonsTestUtility.java │ │ ├── hasher │ │ └── ConcurrentStreamingTreeHasherTest.java │ │ └── utils │ │ ├── ChunkUtilsTest.java │ │ ├── FileUtilitiesTest.java │ │ ├── MathUtilitiesTest.java │ │ ├── PreconditionsTest.java │ │ └── StringUtilitiesTest.java │ └── resources │ ├── invalid1.gz │ ├── valid1.blk │ ├── valid1.txt.gz │ ├── valid2.blk │ └── valid2.txt.gz ├── ct.yaml ├── docs ├── Block-Node-Types.md ├── assets │ ├── 00036-consumer-registration.png │ ├── 00036-demo-disruptor-class-diagram.png │ ├── 00036-producer-registration.png │ ├── 00036-refactor-demo-disruptor.png │ ├── Block-Node-Nano-Services.svg │ ├── Block-Node-Tiers-and-Types.svg │ └── Multi-Publisher-Diagram.svg ├── block-node │ ├── README.md │ ├── configuration.md │ ├── metrics.md │ └── quickstart.md ├── configuration.md ├── contributing ├── design │ ├── apis │ │ └── server-status-api.md │ ├── architecture │ │ └── Nano-Service-Approach.md │ ├── backfill-plugin.md │ ├── block-verification.md │ ├── communication-protocol │ │ ├── README.md │ │ └── publish-block-stream.md │ ├── design-doc-template.md │ ├── how-to-design-doc.md │ ├── persistence │ │ ├── Addenda │ │ │ └── BlockPersistenceTaskBasedWriter.md │ │ ├── block-node-retention-policy.md │ │ └── block-persistence.md │ ├── proofs │ │ └── block-content-proof.md │ └── streaming │ │ ├── bidi-producer-consumers-streaming.md │ │ ├── closed-range-historic-streaming.md │ │ └── open-range-historic-streaming.md ├── logging-guidelines.md ├── overview.md ├── release.md ├── simulator │ ├── README.md │ ├── configuration.md │ └── quickstart.md ├── test-plan │ ├── files-historic-persistence-e2e-test-plan.md │ ├── persistence │ │ └── files-recent-persistence-e2e-test-plan.md │ └── template.md └── tools │ ├── README.md │ └── quickstart.md ├── gradle.properties ├── gradle ├── aggregation │ └── build.gradle.kts ├── modules.properties ├── toolchain-versions.properties └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── hiero-dependency-versions └── build.gradle.kts ├── protobuf-sources ├── .gitignore ├── build.gradle.kts ├── scripts │ └── build-bn-proto.sh └── src │ └── main │ ├── java │ └── module-info.java │ └── proto │ ├── block-node │ └── api │ │ ├── block_access_service.proto │ │ ├── block_stream_publish_service.proto │ │ ├── block_stream_subscribe_service.proto │ │ ├── node_service.proto │ │ ├── proof_service.proto │ │ ├── reconnect_service.proto │ │ ├── shared_message_types.proto │ │ └── state_service.proto │ └── internal │ └── unparsed.proto ├── settings.gradle.kts ├── tool.sh ├── tools-and-tests ├── protobuf-protoc │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── module-info.java ├── simulator │ ├── build.gradle.kts │ ├── docker │ │ ├── Dockerfile │ │ ├── docker-compose-publisher-consumer.yml │ │ ├── docker-compose-publisher.yml │ │ └── update-env.sh │ └── src │ │ ├── main │ │ ├── java │ │ │ ├── module-info.java │ │ │ └── org │ │ │ │ └── hiero │ │ │ │ └── block │ │ │ │ └── simulator │ │ │ │ ├── BlockStreamSimulator.java │ │ │ │ ├── BlockStreamSimulatorApp.java │ │ │ │ ├── BlockStreamSimulatorInjectionComponent.java │ │ │ │ ├── Constants.java │ │ │ │ ├── config │ │ │ │ ├── ConfigInjectionModule.java │ │ │ │ ├── SimulatorConfigExtension.java │ │ │ │ ├── SimulatorMappedConfigSourceInitializer.java │ │ │ │ ├── data │ │ │ │ │ ├── BlockGeneratorConfig.java │ │ │ │ │ ├── BlockStreamConfig.java │ │ │ │ │ ├── ConsumerConfig.java │ │ │ │ │ ├── GrpcConfig.java │ │ │ │ │ ├── SimulatorStartupDataConfig.java │ │ │ │ │ ├── StreamStatus.java │ │ │ │ │ └── UnorderedStreamConfig.java │ │ │ │ ├── logging │ │ │ │ │ ├── ConfigurationLogging.java │ │ │ │ │ ├── Loggable.java │ │ │ │ │ └── SimulatorConfigurationLogger.java │ │ │ │ └── types │ │ │ │ │ ├── GenerationMode.java │ │ │ │ │ ├── MidBlockFailType.java │ │ │ │ │ ├── SimulatorMode.java │ │ │ │ │ ├── SlowDownType.java │ │ │ │ │ └── StreamingMode.java │ │ │ │ ├── exception │ │ │ │ └── BlockSimulatorParsingException.java │ │ │ │ ├── generator │ │ │ │ ├── BlockAsFileBlockStreamManager.java │ │ │ │ ├── BlockAsFileLargeDataSets.java │ │ │ │ ├── BlockStreamManager.java │ │ │ │ ├── CraftBlockStreamManager.java │ │ │ │ ├── GeneratorInjectionModule.java │ │ │ │ └── itemhandler │ │ │ │ │ ├── AbstractBlockItemHandler.java │ │ │ │ │ ├── BlockHeaderHandler.java │ │ │ │ │ ├── BlockProofHandler.java │ │ │ │ │ ├── EventHeaderHandler.java │ │ │ │ │ ├── EventTransactionHandler.java │ │ │ │ │ ├── ItemHandler.java │ │ │ │ │ └── TransactionResultHandler.java │ │ │ │ ├── grpc │ │ │ │ ├── ConsumerStreamGrpcClient.java │ │ │ │ ├── GrpcInjectionModule.java │ │ │ │ ├── PublishStreamGrpcClient.java │ │ │ │ ├── PublishStreamGrpcServer.java │ │ │ │ └── impl │ │ │ │ │ ├── ConsumerStreamGrpcClientImpl.java │ │ │ │ │ ├── ConsumerStreamObserver.java │ │ │ │ │ ├── PublishStreamGrpcClientImpl.java │ │ │ │ │ ├── PublishStreamGrpcServerImpl.java │ │ │ │ │ ├── PublishStreamObserver.java │ │ │ │ │ └── PublishStreamServerObserver.java │ │ │ │ ├── metrics │ │ │ │ ├── MetricsInjectionModule.java │ │ │ │ ├── MetricsService.java │ │ │ │ ├── MetricsServiceImpl.java │ │ │ │ └── SimulatorMetricTypes.java │ │ │ │ ├── mode │ │ │ │ ├── SimulatorModeHandler.java │ │ │ │ ├── SimulatorModeInjectionModule.java │ │ │ │ └── impl │ │ │ │ │ ├── ConsumerModeHandler.java │ │ │ │ │ ├── PublisherClientModeHandler.java │ │ │ │ │ └── PublisherServerModeHandler.java │ │ │ │ └── startup │ │ │ │ ├── SimulatorStartupData.java │ │ │ │ ├── StartupDataInjectionModule.java │ │ │ │ └── impl │ │ │ │ └── SimulatorStartupDataImpl.java │ │ └── resources │ │ │ ├── app.properties │ │ │ └── logging.properties │ │ └── test │ │ ├── java │ │ └── org │ │ │ └── hiero │ │ │ └── block │ │ │ └── simulator │ │ │ ├── BlockStreamSimulatorTest.java │ │ │ ├── StackTracesTest.java │ │ │ ├── TestUtils.java │ │ │ ├── config │ │ │ ├── ConfigInjectionModuleTest.java │ │ │ ├── SimulatorMappedConfigSourceInitializerTest.java │ │ │ ├── data │ │ │ │ ├── BlockStreamConfigTest.java │ │ │ │ ├── StreamStatusTest.java │ │ │ │ └── UnorderedStreamConfigTest.java │ │ │ ├── logging │ │ │ │ ├── SimulatorConfigurationLoggerTest.java │ │ │ │ └── TestSecretConfig.java │ │ │ └── types │ │ │ │ ├── GenerationModeTest.java │ │ │ │ └── StreamingModeTest.java │ │ │ ├── generator │ │ │ ├── BlockAsFileBlockStreamManagerTest.java │ │ │ ├── BlockAsFileLargeDataSetsTest.java │ │ │ ├── CraftBlockStreamManagerTest.java │ │ │ ├── GeneratorInjectionModuleTest.java │ │ │ └── itemhandler │ │ │ │ ├── AbstractBlockItemHandlerTest.java │ │ │ │ ├── BlockHeaderHandlerTest.java │ │ │ │ ├── BlockProofHandlerTest.java │ │ │ │ ├── EventHeaderHandlerTest.java │ │ │ │ ├── EventTransactionHandlerTest.java │ │ │ │ └── TransactionResultHandlerTest.java │ │ │ ├── grpc │ │ │ └── impl │ │ │ │ ├── ConsumerStreamGrpcClientImplTest.java │ │ │ │ ├── ConsumerStreamObserverTest.java │ │ │ │ ├── PublishStreamGrpcClientImplTest.java │ │ │ │ ├── PublishStreamGrpcServerImplTest.java │ │ │ │ ├── PublishStreamObserverTest.java │ │ │ │ └── PublishStreamServerObserverTest.java │ │ │ ├── metrics │ │ │ ├── MetricsInjectionModuleTest.java │ │ │ └── MetricsServiceTest.java │ │ │ ├── mode │ │ │ ├── ConsumerModeHandlerTest.java │ │ │ ├── PublisherClientModeHandlerTest.java │ │ │ └── PublisherServerModeHandlerTest.java │ │ │ └── startup │ │ │ └── impl │ │ │ └── SimulatorStartupDataImplTest.java │ │ └── resources │ │ └── block-0.0.3-blk │ │ ├── 000000000000000000000000000000000000.blk │ │ ├── 000000000000000000000000000000000001.blk │ │ ├── 000000000000000000000000000000000002.blk │ │ ├── 000000000000000000000000000000000003.blk │ │ ├── 000000000000000000000000000000000004.blk │ │ ├── 000000000000000000000000000000000005.blk │ │ ├── 000000000000000000000000000000000006.blk │ │ ├── 000000000000000000000000000000000007.blk │ │ ├── 000000000000000000000000000000000008.blk │ │ └── notABlock.txt ├── suites │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ ├── module-info.java │ │ └── org │ │ └── hiero │ │ └── block │ │ └── suites │ │ ├── BaseSuite.java │ │ ├── ErrorLoggingExecutor.java │ │ ├── block │ │ └── access │ │ │ ├── BlockAccessTestSuites.java │ │ │ └── GetBlockApiTests.java │ │ ├── grpc │ │ ├── GrpcTestSuites.java │ │ ├── negative │ │ │ └── NegativeServerAvailabilityTests.java │ │ └── positive │ │ │ ├── PositiveEndpointBehaviourTests.java │ │ │ └── PositiveServerAvailabilityTests.java │ │ ├── metrics │ │ ├── MetricsAccessor.java │ │ ├── MetricsCommonTests.java │ │ └── MetricsTestSuites.java │ │ ├── persistence │ │ ├── DataPersistenceTestSuites.java │ │ └── positive │ │ │ └── PositiveDataPersistenceTests.java │ │ ├── publisher │ │ ├── PublisherTestSuites.java │ │ └── positive │ │ │ └── PositiveMultiplePublishersTests.java │ │ ├── server │ │ └── status │ │ │ ├── ServerStatusTestSuites.java │ │ │ └── positive │ │ │ └── PositiveServerStatusTests.java │ │ ├── subscriber │ │ ├── SubscriberTestSuites.java │ │ ├── negative │ │ │ └── NegativeSingleSubscriberTests.java │ │ └── positive │ │ │ ├── PositiveMultipleSubscribersTests.java │ │ │ └── PositiveSingleSubscriberTests.java │ │ ├── utils │ │ ├── BlockAccessUtils.java │ │ ├── BlockSimulatorUtils.java │ │ └── ServerStatusUtils.java │ │ └── verification │ │ ├── BlockVerificationTestSuites.java │ │ └── VerificationCommonTests.java └── tools │ ├── build.gradle.kts │ └── src │ └── main │ └── java │ └── org │ └── hiero │ └── block │ └── tools │ ├── BlockStreamTool.java │ └── commands │ ├── BlockInfo.java │ ├── ConvertToJson.java │ └── record2blocks │ ├── Record2BlockCommand.java │ ├── gcp │ ├── AddNewerBlockTimes.java │ └── MainNetBucket.java │ ├── mirrornode │ ├── ExtractBlockTimes.java │ ├── FetchBlockQuery.java │ ├── FetchMirrorNodeRecordsCsv.java │ └── ValidateBlockTimes.java │ ├── model │ ├── BlockInfo.java │ ├── BlockTimes.java │ ├── ChainFile.java │ ├── ChainFileAndCount.java │ ├── NumberedSidecarFile.java │ ├── ParsedSignatureFile.java │ └── RecordFileInfo.java │ └── util │ ├── BlockWriter.java │ └── RecordFileDates.java └── version.txt /.github/ISSUE_TEMPLATE/01-Story-Template.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | name: Agile Task or Feature 3 | description: Create a new task or feature 4 | projects: 5 | - "hiero-ledger/9" 6 | type: feature 7 | body: 8 | - type: textarea 9 | id: Story-Form 10 | attributes: 11 | label: Story Form 12 | description: | 13 | As a "Persona" 14 | I want to "Request" 15 | So that "Goal" 16 | value: | 17 | As a ? 18 | I want to ? 19 | So that ? 20 | validations: 21 | required: true 22 | - type: textarea 23 | id: technical-notes 24 | attributes: 25 | label: Technical Notes 26 | description: Add any additional detail to describe this story. 27 | placeholder: | 28 | Technical details, notes, suggestions, etc... 29 | validations: 30 | required: true 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02-Epic-Template.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | name: Epic 3 | description: Create a new Epic 4 | projects: 5 | - "hiero-ledger/9" 6 | type: "epic" 7 | body: 8 | - type: textarea 9 | id: epic-goal 10 | attributes: 11 | label: Goal 12 | description: Describe the goal of this epic in one or two sentences 13 | placeholder: | 14 | Make the block node spectacular. 15 | validations: 16 | required: true 17 | - type: textarea 18 | id: epic-intention 19 | attributes: 20 | label: Intention 21 | description: Three to five sentences about what the team intends to accomplish in order to meet the epic goal. 22 | placeholder: | 23 | Three to five sentences about what the team intends to accomplish in order to meet the epic goal. 24 | validations: 25 | required: true 26 | - type: textarea 27 | id: epic-considerations 28 | attributes: 29 | label: Considerations 30 | description: A list of considerations that affect the completion of this epic. 31 | placeholder: | 32 | A list of considerations that affect the completion of this epic. This includes alternatives already considered before arriving at the intention above. 33 | - Consideration 1 34 | - Added details 35 | - Consideration 2 36 | - Added details 37 | - ... 38 | validations: 39 | required: false 40 | - type: textarea 41 | id: epic-detail 42 | attributes: 43 | label: Technical Details 44 | description: Add any additional detail to describe this epic. 45 | placeholder: | 46 | Technical details, notes, customer stories, etc... 47 | validations: 48 | required: false 49 | - type: textarea 50 | id: task-list 51 | attributes: 52 | label: Tasks and Features 53 | description: List features and tasks needed to complete this epic 54 | placeholder: | 55 | - [ ] feature 1 56 | - [ ] feature 2 57 | - [ ] task 1 58 | - [ ] ... 59 | validations: 60 | required: false 61 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/03-Bug-Template.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | name: Block Node Bug Report 3 | description: Create a report to help us improve 4 | projects: 5 | - "hiero-ledger/9" 6 | labels: 7 | - bug 8 | type: "Bug" 9 | body: 10 | - type: markdown 11 | attributes: 12 | value: | 13 | ## Thanks for submitting a bug report! 14 | 15 | Before submitting: 16 | 1. Try searching the existing issues and discussions to see if your issue has already been reported 17 | 2. If you're reporting a security vulnerability, please disclose responsibly via our [bug bounty program](https://hedera.com/bounty) 18 | - type: textarea 19 | id: description 20 | attributes: 21 | label: Description 22 | description: What happened and what you did you expect to happen? 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: steps 27 | attributes: 28 | label: Steps to Reproduce 29 | description: Steps to reproduce the behavior 30 | placeholder: | 31 | 1. Run the block node 32 | 2. Send a '...' request 33 | 3. Response is '...' 34 | validations: 35 | required: false 36 | - type: textarea 37 | id: context 38 | attributes: 39 | label: Additional context 40 | description: Attach any logs or screenshots relevant to the problem. 41 | placeholder: | 42 | ![Screenshot](bug.png) 43 | 44 | ```bash 45 | 2021-06-29T13:50:45.008-0600 INFO thread-1 Some logs 46 | ``` 47 | validations: 48 | required: false 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | blank_issues_enabled: true 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | version: 2 3 | updates: 4 | - package-ecosystem: github-actions 5 | directory: / 6 | schedule: 7 | interval: daily 8 | open-pull-requests-limit: 10 9 | 10 | - package-ecosystem: docker 11 | directory: /auth-layer-proxy 12 | schedule: 13 | interval: daily 14 | 15 | - package-ecosystem: gradle 16 | directory: /hiero-dependency-versions 17 | schedule: 18 | interval: weekly 19 | 20 | - package-ecosystem: gradle 21 | directory: / 22 | schedule: 23 | interval: weekly 24 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Reviewer Notes 2 | 3 | ## Related Issue(s) 4 | Use keywords `Fix, Fixes, Fixed, Close, Closes, Closed, Resolve, Resolves, Resolved` 5 | to connect an issue to be closed by this pull request. 6 | -------------------------------------------------------------------------------- /.github/release.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | changelog: 3 | exclude: 4 | labels: ["wontfix", "question", "duplicate", "invalid"] 5 | categories: 6 | - title: "⭐ New Features" 7 | labels: ["New Feature"] 8 | - title: "🚀 Enhancements" 9 | labels: ["Feature Enhancement"] 10 | - title: "🐛 Bug Fixes" 11 | labels: ["Bug"] 12 | - title: "🔨 Tests" 13 | labels: ["Tests"] 14 | - title: "📝 Documentation" 15 | labels: ["Documentation", "Design"] 16 | - title: "🔒 Security" 17 | labels: ["Security"] 18 | - title: "🔧 Improvements" 19 | labels: ["Improvement"] 20 | - title: "🔥 Breaking Changes" 21 | labels: ["Breaking Change"] 22 | - title: "⬆️ Dependency Upgrades" 23 | labels: ["dependencies"] 24 | sort: "desc" 25 | transformers: 26 | - pattern: "^feat: (.*)$" 27 | target: "Feature: $1" 28 | - pattern: "^fix: (.*)$" 29 | target: "Fix: $1" 30 | - pattern: "^docs: (.*)$" 31 | target: "Docs: $1" 32 | - pattern: "^style: (.*)$" 33 | target: "Style: $1" 34 | - pattern: "^refactor: (.*)$" 35 | target: "Refactor: $1" 36 | - pattern: "^perf: (.*)$" 37 | target: "Performance: $1" 38 | - pattern: "^test: (.*)$" 39 | target: "Test: $1" 40 | - pattern: "^chore: (.*)$" 41 | target: "Chore: $1" 42 | - pattern: "^revert: (.*)$" 43 | target: "Revert: $1" 44 | - pattern: "^security: (.*)$" 45 | target: "Security: $1" 46 | - pattern: "^build: (.*)$" 47 | target: "Build: $1" 48 | - pattern: "^ci: (.*)$" 49 | target: "CI: $1" 50 | template: | 51 | # $RELEASE_TITLE 52 | 53 | **Release Date:** $RELEASE_DATE 54 | 55 | ## Changes 56 | 57 | $CHANGES 58 | 59 | ## ❤️ Contributors 60 | 61 | $CONTRIBUTORS 62 | 63 | --- 64 | 65 | ## 📜 Full Changelog 66 | 67 | [View the full changelog]($COMPARE_URL) 68 | -------------------------------------------------------------------------------- /.github/workflows/e2e-tests.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | name: "E2E Test Suites" 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - release/* 8 | pull_request: 9 | types: 10 | - opened 11 | - reopened 12 | - synchronize 13 | 14 | defaults: 15 | run: 16 | shell: bash 17 | 18 | permissions: 19 | contents: read 20 | 21 | env: 22 | GRADLE_EXEC: "ionice -c 2 -n 2 nice -n 19 ./gradlew " 23 | 24 | jobs: 25 | e2e-tests: 26 | timeout-minutes: 30 27 | runs-on: hiero-block-node-linux-medium 28 | steps: 29 | - name: Harden Runner 30 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 31 | with: 32 | egress-policy: audit 33 | 34 | - name: Checkout code 35 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 36 | with: 37 | fetch-depth: 0 38 | 39 | - name: Expand Shallow Clone for Spotless 40 | run: | 41 | if [ -f .git/shallow ]; then 42 | git fetch --unshallow --no-recurse-submodules 43 | else 44 | echo "Repository is not shallow, no need to unshallow." 45 | fi 46 | 47 | - name: Set up JDK 21 48 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 49 | with: 50 | distribution: "temurin" 51 | java-version: "21.0.6" 52 | 53 | - name: Run Acceptance Tests 54 | id: acceptance-tests 55 | run: ${GRADLE_EXEC} runSuites 56 | -------------------------------------------------------------------------------- /.github/workflows/local-node-test.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | name: "Local Node E2E Tests" 3 | 4 | on: 5 | push: 6 | branches: [main] 7 | tags: ["v*"] 8 | 9 | jobs: 10 | smart-contracts-tests: 11 | uses: ./.github/workflows/local-node-test-reusable.yaml 12 | with: 13 | networkNodeTag: "" 14 | mirrorNodeTag: "" 15 | relayTag: "" 16 | branch: ${{ github.event.pull_request.head.ref || github.ref_name }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | bin/ 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.nar 18 | *.ear 19 | *.zip 20 | *.tar.gz 21 | *.rar 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | replay_pid* 26 | 27 | # Gradle files 28 | .gradle 29 | **/build/ 30 | !src/**/build/ 31 | 32 | # Ignore Gradle GUI config 33 | gradle-app.setting 34 | 35 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 36 | !gradle-wrapper.jar 37 | 38 | # Avoid ignore Gradle wrapper properties 39 | !gradle-wrapper.properties 40 | 41 | # Cache of project 42 | .gradletasknamecache 43 | 44 | # Eclipse Gradle plugin generated files 45 | # Eclipse Core 46 | .project 47 | 48 | # JDT-specific (Eclipse Java Development Tools) 49 | .classpath 50 | 51 | .idea 52 | .DS_Store 53 | 54 | # .env files (from anywhere) 55 | .env 56 | 57 | server/data/ 58 | /tools/data/ 59 | 60 | # manual test files 61 | server/src/test/resources/test_output/ 62 | 63 | # protobuf artifcate related dirs 64 | protobuf-sources/block-node-protobuf/ 65 | protobuf-sources/hiero-consensus-node/ 66 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | 3 | The general handling of Maintainer rights and all groups in this GitHub org is done in the repository. 4 | 5 | ## Maintainer Scopes, GitHub Roles and GitHub Teams 6 | 7 | Maintainers are assigned the following scopes in this repository: 8 | 9 | | Scope | Definition | GitHub Role | GitHub Team | 10 | |---------------------|-----------------------------------|-------------|--------------------------------| 11 | | project-maintainers | The Maintainers of the project | Maintain | `hiero-block-node-maintainers` | 12 | | tsc | The Hiero TSC | Maintain | `tsc` | 13 | | github-maintainers | The Maintainers of the github org | Maintain | `github-maintainers` | 14 | 15 | ## Active Maintainers 16 | 17 | 18 | 19 | | Name | GitHub ID | Scope | LFID | Discord ID | Email | Company Affiliation | 20 | |-----------------------|-------------------|-------|------|------------|-------|---------------------| 21 | | Nana Essilfie-Conduah | Nana-EC | | | | | Hashgraph | 22 | | Alfredo Gutierrez | AlfredoG87 | | | | | Hashgraph | 23 | | Jasper Potts | jasperpotts | | | | | Hashgraph | 24 | | Matt Peterson | mattp-swirldslabs | | | | | | 25 | 26 | ## Emeritus Maintainers 27 | 28 | | Name | GitHub ID | Scope | LFID | Discord ID | Email | Company Affiliation | 29 | |------|-----------|-------|------|------------|-------|---------------------| 30 | | | | | | | | | 31 | 32 | ## The Duties of a Maintainer 33 | 34 | Maintainers are expected to perform duties in alignment with **[Hiero-Ledger's defined maintainer guidelines](https://github.com/hiero-ledger/governance/blob/main/roles-and-groups.md#maintainers).** 35 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Please do not file a public ticket mentioning the vulnerability. To report a vulnerability, please send an email to [security@hashgraph.com](security@hashgraph.com). 6 | -------------------------------------------------------------------------------- /block-node/README.md: -------------------------------------------------------------------------------- 1 | # Block Node Application 2 | 3 | ## Table of Contents 4 | 5 | 1. [Overview](#overview) 6 | 2. [Prerequisites](#prerequisites) 7 | 3. [Configuration](#configuration) 8 | 4. [Metrics](#metrics) 9 | 5. [Design](#design) 10 | 1. [Block Persistence](#block-persistence) 11 | 2. [Bi-directional Producer/Consumer Streaming with gRPC](#bi-directional-producerconsumer-streaming-with-grpc) 12 | 13 | ## Overview 14 | 15 | The Block Stream Application is designed handle the output of a Hiero Node, which would be in form of Block Stream. 16 | By handling we can understand verifying, storing and applying needed state changes. 17 | It uses various configuration sources and dependency injection to manage its components. 18 | 19 | ## Configuration 20 | 21 | Refer to the [Configuration](docs/configuration.md) for configuration options. 22 | 23 | ## Quickstart 24 | 25 | Refer to the [Quickstart](docs/quickstart.md) for a quick guide on how to get started with the application. 26 | 27 | ## Metrics 28 | 29 | Refer to the [Metrics](docs/metrics.md) for metrics available in the system. 30 | 31 | ## Design 32 | 33 | ### Block Persistence 34 | 35 | Refer to the [Block Persistence](docs/design/block-persistence.md) for details on how blocks are persisted. 36 | 37 | ### Bi-directional Producer/Consumer Streaming with gRPC 38 | 39 | Refer to the [Bi-directional Producer/Consumer Streaming with gRPC](docs/design/live-streaming/bidi-producer-consumers-streaming.md) for details on how the gRPC streaming is implemented. 40 | -------------------------------------------------------------------------------- /block-node/app/docker/.dockerignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.md 3 | *.sw* 4 | *.csv 5 | 6 | mvnw* 7 | LICENSE* 8 | 9 | .java-version 10 | -------------------------------------------------------------------------------- /block-node/app/docker/README.md: -------------------------------------------------------------------------------- 1 | This folder contains file that are used to start the block node server as docker container. 2 | All docker workflows are defined with a corresponding gradle task. No script or file in this folder should be called 'by hand'. 3 | 4 | Gradle tasks are of group `docker` 5 | - updateDockerEnv 6 | - createDockerImage 7 | - startDockerContainer 8 | - stopDockerContainer 9 | -------------------------------------------------------------------------------- /block-node/app/docker/docker-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ $# -lt 1 ]]; then 4 | echo "Usage: ${0} [version] [project_dir]" 5 | exit 1 6 | fi 7 | 8 | VERSION=$1 9 | 10 | echo "Building image [block-node-server:${VERSION}]" 11 | echo 12 | 13 | SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) 14 | # run docker build 15 | docker buildx build --load -t "block-node-server:${VERSION}" \ 16 | --build-context distributions=../distributions \ 17 | --build-arg VERSION="${VERSION}" \ 18 | --build-arg SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH}" . || exit "${?}" 19 | 20 | echo 21 | echo "Image [block-node-server:${VERSION}] built successfully!" 22 | -------------------------------------------------------------------------------- /block-node/app/docker/loki-config.yaml: -------------------------------------------------------------------------------- 1 | auth_enabled: false 2 | server: 3 | http_listen_port: 3100 4 | grpc_listen_port: 9096 5 | common: 6 | instance_addr: 127.0.0.1 7 | path_prefix: /tmp/loki 8 | storage: 9 | filesystem: 10 | chunks_directory: /tmp/loki/chunks 11 | rules_directory: /tmp/loki/rules 12 | replication_factor: 1 13 | ring: 14 | kvstore: 15 | store: inmemory 16 | query_range: 17 | results_cache: 18 | cache: 19 | embedded_cache: 20 | enabled: true 21 | max_size_mb: 100 22 | schema_config: 23 | configs: 24 | - from: 2020-10-24 25 | store: tsdb 26 | object_store: filesystem 27 | schema: v13 28 | index: 29 | prefix: index_ 30 | period: 24h 31 | ruler: 32 | alertmanager_url: http://localhost:9093 33 | analytics: 34 | reporting_enabled: false 35 | -------------------------------------------------------------------------------- /block-node/app/docker/metrics/dashboards/provisioner.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: 'default' 5 | orgId: 1 6 | folder: '' 7 | folderUid: '' 8 | type: file 9 | disableDeletion: false 10 | updateIntervalSeconds: 10 11 | allowUiUpdates: true 12 | options: 13 | path: /etc/grafana/provisioning/dashboards 14 | foldersFromFilesStructure: true 15 | -------------------------------------------------------------------------------- /block-node/app/docker/metrics/datasources/datasources.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Prometheus 5 | type: prometheus 6 | uid: prometheus 7 | access: proxy 8 | url: http://prometheus:9090 9 | isDefault: true 10 | editable: true 11 | jsonData: 12 | timeInterval: 1s 13 | 14 | - name: Loki 15 | type: loki 16 | access: proxy 17 | orgId: 1 18 | url: http://loki:3100 19 | basicAuth: false 20 | isDefault: false 21 | version: 1 22 | editable: true 23 | -------------------------------------------------------------------------------- /block-node/app/docker/metrics/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 1s 3 | 4 | scrape_configs: 5 | - job_name: 'local' 6 | static_configs: 7 | - targets: ['block-node-server:9999', 'cadvisor:8080'] 8 | 9 | - job_name: 'simulator-publisher' 10 | static_configs: 11 | - targets: ['simulator-publisher:9998'] 12 | metrics_path: '/metrics' 13 | scheme: 'http' 14 | relabel_configs: 15 | - source_labels: [__name__] 16 | target_label: instance_type 17 | replacement: 'publisher' 18 | 19 | - job_name: 'simulator-consumer' 20 | static_configs: 21 | - targets: ['simulator-consumer:9997'] 22 | metrics_path: '/metrics' 23 | scheme: 'http' 24 | relabel_configs: 25 | - source_labels: [__name__] 26 | target_label: instance_type 27 | replacement: 'consumer' 28 | -------------------------------------------------------------------------------- /block-node/app/docker/promtail-config.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http_listen_port: 9080 3 | grpc_listen_port: 0 4 | clients: 5 | - url: http://loki:3100/loki/api/v1/push 6 | positions: 7 | filename: /tmp/positions.yaml 8 | scrape_configs: 9 | # Docker Service Discovery 10 | - job_name: docker-logs 11 | docker_sd_configs: 12 | - host: unix:///var/run/docker.sock 13 | pipeline_stages: 14 | - docker: 15 | docker_url: unix:///var/run/docker.sock 16 | # This multiline stage merges multiple lines for one exception stack trace 17 | # into a single log message. 18 | - multiline: 19 | # firstline: A regex that identifies the start of a new log entry 20 | firstline: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}' 21 | # Maximum wait time for more lines before sending the collected log upstream 22 | max_wait_time: 3s 23 | relabel_configs: 24 | - source_labels: [__meta_docker_container_name] 25 | regex: "/(.*)" 26 | replacement: "$1" 27 | target_label: container_name 28 | - source_labels: [__meta_docker_container_image] 29 | target_label: image 30 | - source_labels: [__meta_docker_container_id] 31 | target_label: container_id 32 | - target_label: job 33 | replacement: docker-logs 34 | -------------------------------------------------------------------------------- /block-node/app/docker/update-env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This scripts create a '.env' file that is used for docker & docker-compose as an input of environment variables. 4 | # This script is called by gradle and get the current project version as an input param 5 | 6 | if [ $# -lt 1 ]; then 7 | # is required! 8 | echo "USAGE: $0 [DEBUG] [SMOKE_TEST]" 9 | exit 1 10 | fi 11 | 12 | project_version=$1 13 | # determine if we should include debug opts 14 | [ "$2" = true ] && is_debug=true || is_debug=false 15 | # determine if we should include smoke test env variables 16 | [ "$3" = true ] && is_smoke_test=true || is_smoke_test=false 17 | 18 | echo "VERSION=$project_version" > .env 19 | echo "REGISTRY_PREFIX=" >> .env 20 | # Storage root path, this is temporary until we have a proper .properties file for all configs 21 | echo "BLOCKNODE_STORAGE_ROOT_PATH=/opt/hiero/block-node/storage" >> .env 22 | 23 | if [ true = "$is_smoke_test" ]; then 24 | # add smoke test variables 25 | echo "MEDIATOR_RING_BUFFER_SIZE=1024" >> .env 26 | echo "NOTIFIER_RING_BUFFER_SIZE=1024" >> .env 27 | echo "JAVA_OPTS='-Xms4G -Xmx4G'" >> .env 28 | else 29 | # Set the production default values 30 | echo "JAVA_OPTS='-Xms16G -Xmx16G'" >> .env 31 | fi 32 | 33 | if [ true = "$is_debug" ]; then 34 | # The server will wait for the debugger to attach on port 5005 35 | # JProfiler can attach on port 8849 36 | echo "JAVA_TOOL_OPTIONS='-Djava.util.logging.config.file=/opt/hiero/block-node/logs/config/logging.properties -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005' -agentpath:/path/to/libjprofilerti.so=port=8849 " >> .env 37 | else 38 | # we set normally the JAVA_TOOL_OPTIONS 39 | # file is mounted in the docker-compose.yml, changes to the file will be reflected in the container by simply restarting it 40 | echo "JAVA_TOOL_OPTIONS='-Djava.util.logging.config.file=/opt/hiero/block-node/logs/config/logging.properties '" >> .env 41 | fi 42 | # Output the values 43 | echo ".env properties:" 44 | cat .env 45 | echo 46 | -------------------------------------------------------------------------------- /block-node/app/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.spi.BlockNodePlugin; 3 | import org.hiero.block.node.spi.blockmessaging.BlockMessagingFacility; 4 | import org.hiero.block.node.spi.historicalblocks.BlockProviderPlugin; 5 | import org.hiero.block.node.spi.historicalblocks.HistoricalBlockFacility; 6 | 7 | module org.hiero.block.node.app { 8 | // it is expected the app module will never export any packages, only use others 9 | uses HistoricalBlockFacility; 10 | uses BlockMessagingFacility; 11 | uses BlockNodePlugin; 12 | uses BlockProviderPlugin; 13 | 14 | // export configuration classes to the config module 15 | exports org.hiero.block.node.app to 16 | com.swirlds.config.impl, 17 | com.swirlds.config.extensions, 18 | org.hiero.block.node.blocks.files.recent; // accessed in tests 19 | 20 | requires com.hedera.pbj.grpc.helidon.config; 21 | requires com.hedera.pbj.grpc.helidon; 22 | requires com.hedera.pbj.runtime; 23 | requires com.swirlds.base; 24 | requires com.swirlds.common; 25 | requires com.swirlds.config.api; 26 | requires com.swirlds.config.extensions; 27 | requires com.swirlds.metrics.api; 28 | requires org.hiero.block.common; 29 | requires org.hiero.block.node.base; 30 | requires org.hiero.block.node.spi; 31 | requires io.helidon.common; 32 | requires io.helidon.webserver; 33 | requires java.logging; // javax.annotation.processing.Generated 34 | requires static transitive com.github.spotbugs.annotations; 35 | requires static java.compiler; 36 | } 37 | -------------------------------------------------------------------------------- /block-node/app/src/main/java/org/hiero/block/node/app/ServerConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.app; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import com.swirlds.config.api.validation.annotation.Max; 7 | import com.swirlds.config.api.validation.annotation.Min; 8 | import org.hiero.block.node.base.Loggable; 9 | 10 | /** 11 | * Use this configuration across the server features 12 | * 13 | *

ServerConfig will have settings for the server. 14 | * 15 | * @param maxMessageSizeBytes the http2 max message/frame size in bytes 16 | * @param port the port the server will listen on 17 | * @param shutdownDelayMillis the delay in milliseconds for the service 18 | */ 19 | @ConfigData("server") 20 | public record ServerConfig( 21 | @Loggable @ConfigProperty(defaultValue = "4_194_304") @Min(10_240) @Max(16_777_215) int maxMessageSizeBytes, 22 | @Loggable @ConfigProperty(defaultValue = "32768") @Min(32768) @Max(Integer.MAX_VALUE) 23 | int socketSendBufferSizeBytes, 24 | @Loggable @ConfigProperty(defaultValue = "32768") @Min(32768) @Max(Integer.MAX_VALUE) 25 | int socketReceiveBufferSizeBytes, 26 | @Loggable @ConfigProperty(defaultValue = "8080") @Min(1024) @Max(65_535) int port, 27 | @Loggable @ConfigProperty(defaultValue = "500") int shutdownDelayMillis) {} 28 | -------------------------------------------------------------------------------- /block-node/app/src/main/java/org/hiero/block/node/app/ServiceBuilderImpl.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.app; 3 | 4 | import com.hedera.pbj.grpc.helidon.PbjRouting; 5 | import com.hedera.pbj.runtime.grpc.ServiceInterface; 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import io.helidon.webserver.http.HttpRouting; 8 | import io.helidon.webserver.http.HttpRouting.Builder; 9 | import io.helidon.webserver.http.HttpService; 10 | import org.hiero.block.node.spi.ServiceBuilder; 11 | 12 | /** 13 | * Default implementation of {@link ServiceBuilder}. That builds HTTP and PBJ GRPC services. 14 | *

15 | * This class is used to register services with the block node. 16 | */ 17 | public class ServiceBuilderImpl implements ServiceBuilder { 18 | /** The HTTP routing builder. */ 19 | private final HttpRouting.Builder httpRoutingBuilder = HttpRouting.builder(); 20 | /** The PBJ GRPC routing builder. */ 21 | private final PbjRouting.Builder pbjRoutingBuilder = PbjRouting.builder(); 22 | 23 | /** 24 | * {@inheritDoc} 25 | */ 26 | @Override 27 | public void registerHttpService(String path, HttpService... service) { 28 | httpRoutingBuilder.register(path, service); 29 | } 30 | 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | @Override 35 | public void registerGrpcService(@NonNull ServiceInterface service) { 36 | pbjRoutingBuilder.service(service); 37 | } 38 | 39 | /** 40 | * Returns the HTTP routing builder. 41 | * 42 | * @return the HTTP routing builder 43 | */ 44 | Builder httpRoutingBuilder() { 45 | return httpRoutingBuilder; 46 | } 47 | 48 | /** 49 | * Returns the GRPC routing builder. 50 | * 51 | * @return the GRPC routing builder 52 | */ 53 | PbjRouting.Builder grpcRoutingBuilder() { 54 | return pbjRoutingBuilder; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /block-node/app/src/main/resources/app.properties: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | prometheus.endpointPortNumber=9999 4 | 5 | # Ring buffer sizes for the mediator and notifier 6 | # with default values. 7 | #mediator.ringBufferSize=4096 8 | #notifier.ringBufferSize=1024 9 | 10 | # Timeout for consumers to wait for block item before timing out. 11 | # Default is 1500 milliseconds. 12 | #consumer.timeoutThresholdMillis=1500 13 | 14 | #Persistence Storage Config 15 | #persistence.storage.liveRootPath= 16 | #persistence.storage.archiveRootPath= 17 | #persistence.storage.type=BLOCK_AS_LOCAL_FILE 18 | #persistence.storage.compression=ZSTD 19 | #persistence.storage.archiveGroupSize=1_000 20 | -------------------------------------------------------------------------------- /block-node/app/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Log Level Values 4 | # 5 | # SEVERE: indicates a critical error or failure 6 | # WARNING: warns of potential issues or errors 7 | # INFO: reports normal operational information 8 | # CONFIG: provides configuration-related information 9 | # FINE: provides detailed debugging information 10 | # FINER: provides finer-grained debugging information 11 | # FINEST: provides the most detailed debugging information 12 | 13 | # Set the default logging level 14 | # Available Levels are (from most verbose to least verbose): 15 | # ALL FINEST FINER FINE CONFIG INFO WARNING SEVERE OFF 16 | .level=FINER 17 | 18 | # Configuration logging 19 | #org.hiero.block.simulator.config.logging.SimulatorConfigurationLogger.level=OFF 20 | 21 | # gRPC Logging Configuration 22 | io.grpc.level = INFO 23 | # Helidon Logging Configuration 24 | io.helidon.level = INFO 25 | 26 | com.sun.jmx.interceptor.level = INFO 27 | javax.management.level = INFO 28 | 29 | ################################################################################ 30 | # Handlers configuration 31 | ################################################################################ 32 | #handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler 33 | handlers = java.util.logging.ConsoleHandler 34 | 35 | ################################################################################ 36 | # ConsoleHandler configuration 37 | ################################################################################ 38 | java.util.logging.ConsoleHandler.level = ALL 39 | java.util.logging.ConsoleHandler.formatter = org.hiero.block.node.app.logging.CleanColorfulFormatter 40 | #org.hiero.block.node.app.logging.CleanColorfulFormatter.format = %TF %/dev/null 24 | # Apply the new latency, jitter, and packet loss configuration 25 | tc qdisc add dev eth0 root handle 1: netem delay ${CURRENT_LATENCY}ms ${JITTER}ms distribution normal loss ${PACKET_LOSS}% 26 | # Apply the bandwidth limitation 27 | tc qdisc add dev eth0 parent 1:1 handle 10: tbf rate ${BANDWIDTH}kbit burst 32kbit latency 50ms 28 | echo "Updated configuration: Latency = ${CURRENT_LATENCY}ms, Jitter = ${JITTER}ms, Bandwidth = ${BANDWIDTH}kbit, Packet Loss = ${PACKET_LOSS}% - (distribution normal)" 29 | } 30 | 31 | # Initial configuration 32 | apply_tc_config 33 | echo "Initial configuration applied: Latency = ${CURRENT_LATENCY}ms, Jitter = ${JITTER}ms, Bandwidth = ${BANDWIDTH}kbit, Packet Loss = ${PACKET_LOSS}% - (distribution normal)" 34 | 35 | while true; do 36 | sleep $INCREASE_TIME 37 | CURRENT_LATENCY=$((CURRENT_LATENCY + 1000)) 38 | if [ $CURRENT_LATENCY -gt $MAX_LATENCY ]; then 39 | CURRENT_LATENCY=$INITIAL_LATENCY 40 | fi 41 | apply_tc_config 42 | done 43 | -------------------------------------------------------------------------------- /block-node/app/src/test/network-latency-simulator/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Setting up test-context" 4 | 5 | mkdir -p test-context 6 | mkdir -p test-context/protos 7 | 8 | cp -R ../../../../protos/src/main/protobuf/*.proto test-context/protos/ 9 | cp ../resources/consumer.sh test-context/ 10 | 11 | # Make sure to make scripts executable 12 | chmod +x test-context/consumer.sh start.sh configure_latency.sh 13 | 14 | echo "Successfully set up test-context" 15 | -------------------------------------------------------------------------------- /block-node/app/src/test/network-latency-simulator/start.sh: -------------------------------------------------------------------------------- 1 | # Print ENV Values 2 | echo "----- Configuration of Consumer Variables: -----" 3 | echo "GRPC_SERVER: $GRPC_SERVER" 4 | echo "GRPC_METHOD: $GRPC_METHOD" 5 | echo "PATH_TO_PROTO: $PATH_TO_PROTO" 6 | echo "PROTO_IMPORT_PATH: $PROTO_IMPORT_PATH" 7 | echo "----- Configuration of Latency Variables: -----" 8 | echo "INITIAL_LATENCY: $INITIAL_LATENCY" 9 | echo "JITTER: $JITTER" 10 | echo "BANDWIDTH: $BANDWIDTH" 11 | echo "INCREASE_TIME: $INCREASE_TIME" 12 | echo "MAX_LATENCY: $MAX_LATENCY" 13 | echo "PACKET_LOSS: $PACKET_LOSS" 14 | 15 | # First Start consumer without any network latency so it connects without issues. 16 | consumer.sh 1 1000 & 17 | # Then start the network latency configuration script. 18 | configure_latency.sh 19 | -------------------------------------------------------------------------------- /block-node/app/src/test/resources/app-test.properties: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Test Properties File 4 | prometheus.endpointEnabled=false 5 | mediator.ringBufferSize=1024 6 | notifier.ringBufferSize=1024 7 | files.recent.liveRootPath=build/tmp/data/liveRootPath 8 | files.historic.rootPath=build/tmp/data/historic 9 | -------------------------------------------------------------------------------- /block-node/app/src/testFixtures/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | module org.hiero.block.node.app.test.fixtures { 3 | exports org.hiero.block.node.app.fixtures; 4 | exports org.hiero.block.node.app.fixtures.async; 5 | exports org.hiero.block.node.app.fixtures.blocks; 6 | exports org.hiero.block.node.app.fixtures.plugintest; 7 | 8 | requires com.hedera.pbj.runtime; 9 | requires com.swirlds.common; 10 | requires com.swirlds.config.api; 11 | requires com.swirlds.metrics.api; 12 | requires org.hiero.block.node.spi; 13 | requires org.hiero.block.protobuf.pbj; 14 | requires io.helidon.webserver; 15 | requires java.logging; 16 | requires org.junit.jupiter.api; 17 | } 18 | -------------------------------------------------------------------------------- /block-node/app/src/testFixtures/java/org/hiero/block/node/app/fixtures/TestUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.app.fixtures; 3 | 4 | import java.util.logging.Level; 5 | import java.util.logging.LogManager; 6 | import java.util.logging.Logger; 7 | 8 | /** 9 | * Generic Test Utilities. 10 | */ 11 | public class TestUtils { 12 | /** 13 | * Enable debug logging for the test. This is useful for debugging test failures. 14 | */ 15 | public static void enableDebugLogging() { 16 | // enable debug System.logger logging 17 | Logger rootLogger = LogManager.getLogManager().getLogger(""); 18 | rootLogger.setLevel(Level.ALL); 19 | for (var handler : rootLogger.getHandlers()) { 20 | handler.setLevel(Level.ALL); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /block-node/app/src/testFixtures/java/org/hiero/block/node/app/fixtures/plugintest/NoBlocksHistoricalBlockFacility.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.app.fixtures.plugintest; 3 | 4 | import org.hiero.block.node.spi.historicalblocks.BlockAccessor; 5 | import org.hiero.block.node.spi.historicalblocks.BlockRangeSet; 6 | import org.hiero.block.node.spi.historicalblocks.HistoricalBlockFacility; 7 | 8 | /** 9 | * A {@link HistoricalBlockFacility} that does not provide any blocks, for testing. 10 | */ 11 | public class NoBlocksHistoricalBlockFacility implements HistoricalBlockFacility { 12 | @Override 13 | public BlockAccessor block(long blockNumber) { 14 | return null; 15 | } 16 | 17 | @Override 18 | public BlockRangeSet availableBlocks() { 19 | return BlockRangeSet.EMPTY; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /block-node/app/src/testFixtures/java/org/hiero/block/node/app/fixtures/plugintest/NoOpServiceBuilder.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.app.fixtures.plugintest; 3 | 4 | import com.hedera.pbj.runtime.grpc.ServiceInterface; 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | import io.helidon.webserver.http.HttpService; 7 | import org.hiero.block.node.spi.ServiceBuilder; 8 | 9 | /** 10 | * A simple no-op implementation of {@link ServiceBuilder} that does nothing. 11 | * To be used for testing purposes only where we need a non-null implementation 12 | * that we do not want to act upon. 13 | */ 14 | public final class NoOpServiceBuilder implements ServiceBuilder { 15 | /** 16 | * No-op implementation, does nothing. 17 | */ 18 | @Override 19 | public void registerHttpService(final String path, final HttpService... service) { 20 | // No-op implementation, does nothing. 21 | } 22 | 23 | /** 24 | * No-op implementation, does nothing. 25 | */ 26 | @Override 27 | public void registerGrpcService(@NonNull final ServiceInterface service) { 28 | // No-op implementation, does nothing. 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /block-node/app/src/testFixtures/java/org/hiero/block/node/app/fixtures/plugintest/TestHealthFacility.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.app.fixtures.plugintest; 3 | 4 | import java.lang.System.Logger.Level; 5 | import java.util.concurrent.atomic.AtomicBoolean; 6 | import org.hiero.block.node.spi.health.HealthFacility; 7 | 8 | /** 9 | * A testing {@link HealthFacility} that always returns {@link State#RUNNING} for the block node state. And fails test 10 | * if the shutdown method is called. 11 | */ 12 | public class TestHealthFacility implements HealthFacility { 13 | /** The logger for this class. */ 14 | private final System.Logger LOGGER = System.getLogger(getClass().getName()); 15 | /** Track if shutdown method was called, for tests that need to know. */ 16 | public final AtomicBoolean shutdownCalled = new AtomicBoolean(false); 17 | /** If the node is running. Can be set by tests that need it to be false */ 18 | public final AtomicBoolean isRunning = new AtomicBoolean(true); 19 | 20 | /** 21 | * {@inheritDoc} 22 | */ 23 | @Override 24 | public State blockNodeState() { 25 | return isRunning.get() ? State.RUNNING : State.SHUTTING_DOWN; 26 | } 27 | 28 | /** 29 | * {@inheritDoc} 30 | */ 31 | @Override 32 | public void shutdown(String className, String reason) { 33 | LOGGER.log(Level.ERROR, "Shutting down " + className + " " + reason); 34 | shutdownCalled.set(true); 35 | isRunning.set(false); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /block-node/app/src/testFixtures/resources/test-blocks/generated-10.blk.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/block-node/app/src/testFixtures/resources/test-blocks/generated-10.blk.gz -------------------------------------------------------------------------------- /block-node/base/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node Base" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("io.helidon.logging.jul") 13 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 14 | } 15 | 16 | testModuleInfo { 17 | requires("org.junit.jupiter.api") 18 | requires("org.junit.jupiter.params") 19 | requires("org.hiero.block.node.app.test.fixtures") 20 | requires("org.assertj.core") 21 | requires("org.mockito") 22 | requires("org.testcontainers") 23 | requires("io.minio") 24 | requires("junit") 25 | requires("org.hiero.block.protobuf.pbj") 26 | } 27 | -------------------------------------------------------------------------------- /block-node/base/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | module org.hiero.block.node.base { 3 | exports org.hiero.block.node.base; 4 | exports org.hiero.block.node.base.ranges; 5 | exports org.hiero.block.node.base.s3; 6 | exports org.hiero.block.node.base.tar; 7 | 8 | requires transitive org.hiero.block.node.spi; 9 | requires com.hedera.pbj.runtime; 10 | requires org.hiero.block.common; 11 | requires com.github.luben.zstd_jni; 12 | requires java.net.http; 13 | requires java.xml; 14 | requires static transitive com.github.spotbugs.annotations; 15 | requires static java.compiler; // javax.annotation.processing.Generated 16 | } 17 | -------------------------------------------------------------------------------- /block-node/base/src/main/java/org/hiero/block/node/base/Loggable.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.base; 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Annotation to mark a configuration field as loggable. So that its value will be logged on server startup. Any 11 | * property without this annotation will still be logged but with its value masked. This is internationally this way 12 | * round so the default is for a property to be considered sensitive and have its value masked. With the aim to avoid 13 | * accidentally logging sensitive information. 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target({ElementType.RECORD_COMPONENT}) 17 | public @interface Loggable {} 18 | -------------------------------------------------------------------------------- /block-node/base/src/main/java/org/hiero/block/node/base/s3/S3ClientException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.base.s3; 3 | 4 | /** 5 | * A checked exception to act as a base for all S3 client exceptions. 6 | */ 7 | public class S3ClientException extends Exception { 8 | public S3ClientException() { 9 | super(); 10 | } 11 | 12 | public S3ClientException(final String message) { 13 | super(message); 14 | } 15 | 16 | public S3ClientException(final Throwable cause) { 17 | super(cause); 18 | } 19 | 20 | public S3ClientException(final String message, final Throwable cause) { 21 | super(message, cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /block-node/base/src/main/java/org/hiero/block/node/base/s3/S3ClientInitializationException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.base.s3; 3 | 4 | public class S3ClientInitializationException extends S3ClientException { 5 | public S3ClientInitializationException() { 6 | super(); 7 | } 8 | 9 | public S3ClientInitializationException(final String message) { 10 | super(message); 11 | } 12 | 13 | public S3ClientInitializationException(final Throwable cause) { 14 | super(cause); 15 | } 16 | 17 | public S3ClientInitializationException(final String message, final Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /block-node/block-access/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node - Block Access Service API Module" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("io.helidon.logging.jul") 13 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 14 | } 15 | 16 | testModuleInfo { 17 | requires("org.junit.jupiter.api") 18 | requires("org.hiero.block.node.app.test.fixtures") 19 | } 20 | -------------------------------------------------------------------------------- /block-node/block-access/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.access.service.BlockAccessServicePlugin; 3 | 4 | module org.hiero.block.node.access.service { 5 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 6 | 7 | requires transitive org.hiero.block.node.spi; 8 | requires transitive org.hiero.block.protobuf.pbj; 9 | requires com.hedera.pbj.runtime; 10 | requires com.swirlds.metrics.api; 11 | 12 | provides org.hiero.block.node.spi.BlockNodePlugin with 13 | BlockAccessServicePlugin; 14 | } 15 | -------------------------------------------------------------------------------- /block-node/block-providers/files.historic/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node - Blocks File Historic Provider" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("org.apache.logging.log4j.slf4j2.impl") 13 | runtimeOnly("io.helidon.logging.jul") 14 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 15 | } 16 | 17 | testModuleInfo { 18 | requires("com.google.common.jimfs") 19 | requires("org.junit.jupiter.api") 20 | requires("org.junit.jupiter.params") 21 | requires("org.assertj.core") 22 | requires("org.hiero.block.node.app.test.fixtures") 23 | runtimeOnly("com.swirlds.metrics.api") 24 | requires("org.mockito") 25 | runtimeOnly("org.mockito.junit.jupiter") 26 | } 27 | -------------------------------------------------------------------------------- /block-node/block-providers/files.historic/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.blocks.files.historic.BlocksFilesHistoricPlugin; 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | module org.hiero.block.node.blocks.files.historic { 6 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 7 | 8 | // export configuration classes to the config module and app 9 | exports org.hiero.block.node.blocks.files.historic to 10 | com.swirlds.config.impl, 11 | com.swirlds.config.extensions, 12 | org.hiero.block.node.app; 13 | 14 | requires transitive com.swirlds.config.api; 15 | requires transitive org.hiero.block.node.base; 16 | requires transitive org.hiero.block.node.spi; 17 | requires com.hedera.pbj.runtime; 18 | requires com.swirlds.metrics.api; 19 | requires org.hiero.block.common; 20 | requires org.hiero.block.protobuf.pbj; 21 | requires com.github.spotbugs.annotations; 22 | 23 | provides org.hiero.block.node.spi.historicalblocks.BlockProviderPlugin with 24 | BlocksFilesHistoricPlugin; 25 | } 26 | -------------------------------------------------------------------------------- /block-node/block-providers/files.historic/src/main/java/org/hiero/block/node/blocks/files/historic/FilesHistoricConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.blocks.files.historic; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import com.swirlds.config.api.validation.annotation.Max; 7 | import com.swirlds.config.api.validation.annotation.Min; 8 | import java.nio.file.Path; 9 | import java.util.Objects; 10 | import org.hiero.block.common.utils.Preconditions; 11 | import org.hiero.block.node.base.CompressionType; 12 | import org.hiero.block.node.base.Loggable; 13 | 14 | /** 15 | * Use this configuration across the files recent plugin. 16 | * 17 | * @param rootPath provides the root path for saving historic blocks 18 | * @param compression compression type to use for the storage. It is assumed this never changes while a node is running 19 | * and has existing files. 20 | * @param powersOfTenPerZipFileContents the number files in a zip file specified in powers of ten. Can can be one of 21 | * 1 = 10, 2 = 100, 3 = 1000, 4 = 10,000, 5 = 100,000, or 6 = 1,000,000 files per 22 | * zip. Changing this is handy for testing, as having to wait for 10,000 blocks to be 23 | * created is a long time. 24 | */ 25 | @ConfigData("files.historic") 26 | public record FilesHistoricConfig( 27 | @Loggable @ConfigProperty(defaultValue = "/opt/hiero/block-node/data/historic") Path rootPath, 28 | @Loggable @ConfigProperty(defaultValue = "ZSTD") CompressionType compression, 29 | @Loggable @ConfigProperty(defaultValue = "4") @Min(1) @Max(6) int powersOfTenPerZipFileContents) { 30 | /** 31 | * Constructor. 32 | */ 33 | public FilesHistoricConfig { 34 | Objects.requireNonNull(rootPath); 35 | Objects.requireNonNull(compression); 36 | Preconditions.requireInRange(powersOfTenPerZipFileContents, 1, 6); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /block-node/block-providers/files.recent/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node - Blocks File Recent Provider" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("org.apache.logging.log4j.slf4j2.impl") 13 | runtimeOnly("io.helidon.logging.jul") 14 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 15 | } 16 | 17 | testModuleInfo { 18 | requires("com.google.common.jimfs") 19 | requires("org.junit.jupiter.api") 20 | requires("org.junit.jupiter.params") 21 | requires("org.assertj.core") 22 | requires("org.hiero.block.node.app") 23 | requires("org.hiero.block.node.app.test.fixtures") 24 | } 25 | -------------------------------------------------------------------------------- /block-node/block-providers/files.recent/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.blocks.files.recent.BlocksFilesRecentPlugin; 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | module org.hiero.block.node.blocks.files.recent { 6 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 7 | 8 | // export configuration classes to the config module and app 9 | exports org.hiero.block.node.blocks.files.recent to 10 | com.swirlds.config.impl, 11 | com.swirlds.config.extensions, 12 | org.hiero.block.node.app; 13 | 14 | requires transitive com.swirlds.config.api; 15 | requires transitive org.hiero.block.node.base; 16 | requires transitive org.hiero.block.node.spi; 17 | requires com.hedera.pbj.runtime; 18 | requires com.swirlds.metrics.api; 19 | requires org.hiero.block.common; 20 | requires org.hiero.block.protobuf.pbj; 21 | requires com.github.luben.zstd_jni; 22 | requires com.github.spotbugs.annotations; 23 | 24 | provides org.hiero.block.node.spi.historicalblocks.BlockProviderPlugin with 25 | BlocksFilesRecentPlugin; 26 | } 27 | -------------------------------------------------------------------------------- /block-node/block-providers/files.recent/src/main/java/org/hiero/block/node/blocks/files/recent/FilesRecentConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.blocks.files.recent; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import java.nio.file.Path; 7 | import java.util.Objects; 8 | import org.hiero.block.common.utils.Preconditions; 9 | import org.hiero.block.node.base.CompressionType; 10 | import org.hiero.block.node.base.Loggable; 11 | 12 | /** 13 | * Use this configuration across the files recent plugin. 14 | * 15 | * @param liveRootPath provides the root path for saving blocks live 16 | * @param compression compression type to use for the storage. It is assumed this never changes while a node is running 17 | * and has existing files. 18 | * @param maxFilesPerDir number of files per directory. This is used to limit the number of files in a directory to avoid 19 | * file system issues. 20 | */ 21 | @ConfigData("files.recent") 22 | public record FilesRecentConfig( 23 | @Loggable @ConfigProperty(defaultValue = "/opt/hiero/block-node/data/live") Path liveRootPath, 24 | @Loggable @ConfigProperty(defaultValue = "ZSTD") CompressionType compression, 25 | @Loggable @ConfigProperty(defaultValue = "3") int maxFilesPerDir) { 26 | /** 27 | * Constructor. 28 | */ 29 | public FilesRecentConfig { 30 | Objects.requireNonNull(liveRootPath); 31 | Objects.requireNonNull(compression); 32 | Preconditions.requirePositive(maxFilesPerDir); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /block-node/health/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node Health Service" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("org.apache.logging.log4j.slf4j2.impl") 13 | runtimeOnly("io.helidon.logging.jul") 14 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 15 | } 16 | 17 | testModuleInfo { 18 | requires("org.junit.jupiter.api") 19 | requires("org.mockito") 20 | requires("org.mockito.junit.jupiter") 21 | } 22 | -------------------------------------------------------------------------------- /block-node/health/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.health.HealthServicePlugin; 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | module org.hiero.block.node.health { 6 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 7 | 8 | requires transitive org.hiero.block.node.spi; 9 | requires transitive io.helidon.webserver; 10 | requires com.github.spotbugs.annotations; 11 | 12 | provides org.hiero.block.node.spi.BlockNodePlugin with 13 | HealthServicePlugin; 14 | } 15 | -------------------------------------------------------------------------------- /block-node/messaging/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node Messaging Facility" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("io.helidon.logging.jul") 13 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 14 | } 15 | 16 | testModuleInfo { 17 | requires("com.hedera.pbj.runtime") 18 | requires("org.hiero.block.protobuf.pbj") 19 | requires("java.logging") 20 | requires("org.junit.jupiter.api") 21 | requires("org.junit.jupiter.params") 22 | requires("com.swirlds.common") 23 | } 24 | -------------------------------------------------------------------------------- /block-node/messaging/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.messaging.BlockMessagingFacilityImpl; 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | module org.hiero.block.node.messaging { 6 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 7 | 8 | // export configuration classes to the config module 9 | exports org.hiero.block.node.messaging to 10 | com.swirlds.config.impl, 11 | com.swirlds.config.extensions, 12 | org.hiero.block.node.app; 13 | 14 | requires transitive com.swirlds.config.api; 15 | requires transitive org.hiero.block.node.spi; 16 | requires com.swirlds.metrics.api; 17 | requires org.hiero.block.common; 18 | requires org.hiero.block.node.base; 19 | requires com.github.spotbugs.annotations; 20 | requires com.lmax.disruptor; 21 | 22 | provides org.hiero.block.node.spi.blockmessaging.BlockMessagingFacility with 23 | BlockMessagingFacilityImpl; 24 | } 25 | -------------------------------------------------------------------------------- /block-node/messaging/src/main/java/org/hiero/block/node/messaging/BlockItemBatchRingEvent.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.messaging; 3 | 4 | import org.hiero.block.node.spi.blockmessaging.BlockItems; 5 | 6 | /** 7 | * Simple mutable container for a BlockNotification. The ring buffer is made up of these events. 8 | */ 9 | public class BlockItemBatchRingEvent { 10 | /** The value to be published to downstream subscribers through the LMAX Disruptor. */ 11 | private BlockItems blockItems; 12 | 13 | /** Constructor for the BlockItemBatchRingEvent class. */ 14 | public BlockItemBatchRingEvent() {} 15 | 16 | /** 17 | * Sets the given value to be published to downstream subscribers through the LMAX Disruptor. 18 | * The value must not be null and the method is thread-safe. 19 | * 20 | * @param blockItems the value to set 21 | */ 22 | public void set(final BlockItems blockItems) { 23 | this.blockItems = blockItems; 24 | } 25 | 26 | /** 27 | * Gets the value of the event from the LMAX Disruptor on the consumer side. The method is 28 | * thread-safe. 29 | * 30 | * @return the value of the event 31 | */ 32 | public BlockItems get() { 33 | return blockItems; 34 | } 35 | 36 | /** 37 | * toString method to provide a string representation of the BlockItemBatchRingEvent for debugging. 38 | * 39 | * @return Debug string representation of the BlockItemBatchRingEvent 40 | */ 41 | @Override 42 | public String toString() { 43 | return "BlockItemBatchRingEvent{" + (blockItems == null ? "empty" : blockItems) + '}'; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /block-node/messaging/src/main/java/org/hiero/block/node/messaging/MessagingConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.messaging; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import org.hiero.block.common.utils.Preconditions; 7 | import org.hiero.block.node.base.Loggable; 8 | 9 | /** 10 | * Configuration for the messaging system. 11 | * 12 | * @param blockItemQueueSize The maximum number of messages that can be queued for processing. This is used to limit the 13 | * number of block item batches that can be in messing queue at any time. Each batch is 14 | * expected to be approximately 100 block items. The bigger the queue, the more memory is use 15 | * but also the more flexibility of subscribers to be out of sync with each other. The queue 16 | * size must be a power of two. 17 | * @param blockNotificationQueueSize The maximum number of block notifications that can be queued for processing. This is 18 | * used to limit the number of block notifications that can be in the queue at any time. 19 | * Notifications can contain a reference to a whole block of data and hence keep a 20 | * whole block in memory. The bigger the queue, the more memory is used. There should 21 | * be no reason to have a big queue. The queue size must be a power of two. 22 | */ 23 | @ConfigData("messaging") 24 | public record MessagingConfig( 25 | @Loggable @ConfigProperty(defaultValue = "1024") int blockItemQueueSize, 26 | @Loggable @ConfigProperty(defaultValue = "256") int blockNotificationQueueSize) { 27 | /** 28 | * Constructor. 29 | */ 30 | public MessagingConfig { 31 | Preconditions.requirePositive(blockItemQueueSize); 32 | Preconditions.requirePowerOfTwo(blockItemQueueSize); 33 | Preconditions.requirePositive(blockNotificationQueueSize); 34 | Preconditions.requirePowerOfTwo(blockNotificationQueueSize); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /block-node/protobuf-pbj/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { 3 | id("org.hiero.gradle.module.library") 4 | // When upgrading pbjVersion, also need to update pbjVersion on 5 | // hiero-dependency-versions/build.gradle.kts 6 | id("com.hedera.pbj.pbj-compiler") version "0.11.8" 7 | } 8 | 9 | description = "Hiero Block Node Protobuf PBJ API" 10 | 11 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 12 | // and then fix the reported issues. 13 | tasks.withType().configureEach { 14 | options.compilerArgs.add("-Xlint:-exports,-deprecation,-removal,-dep-ann") 15 | } 16 | 17 | tasks.javadoc { 18 | options { 19 | this as StandardJavadocDocletOptions 20 | // There are violations in the generated pbj code 21 | addStringOption("Xdoclint:-reference,-html", "-quiet") 22 | } 23 | } 24 | 25 | pbj { generateTestClasses = false } 26 | 27 | sourceSets { 28 | main { 29 | pbj { 30 | // use sources from 'protobuf' module 31 | srcDir(layout.projectDirectory.dir("../../protobuf-sources/src/main/proto")) 32 | // use sources from CN repository cloned by 'protobuf' module (see task dependency) 33 | srcDir(layout.projectDirectory.dir("../../protobuf-sources/block-node-protobuf")) 34 | // exclude BN files at root level 35 | exclude("*.proto") 36 | } 37 | } 38 | } 39 | 40 | // jjohannes: remove cross-project task dependency once the following issue is addressed 41 | // https://github.com/hiero-ledger/hiero-gradle-conventions/issues/185 42 | tasks.generatePbjSource { dependsOn(":block-node-protobuf-sources:generateBlockNodeProtoArtifact") } 43 | 44 | tasks.test { 45 | // we can exclude the standard protobuf generated tests as we don't need to test them again here 46 | // this speeds up the block node project test run no end :-) 47 | exclude("**com/hedera/**") 48 | } 49 | -------------------------------------------------------------------------------- /block-node/s3-archive/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node - S3 Archive Plugin" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("org.apache.logging.log4j.slf4j2.impl") 13 | runtimeOnly("io.helidon.logging.jul") 14 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 15 | } 16 | 17 | testModuleInfo { 18 | requires("org.junit.jupiter.api") 19 | requires("org.hiero.block.node.app.test.fixtures") 20 | requires("org.testcontainers") 21 | requires("io.minio") 22 | } 23 | -------------------------------------------------------------------------------- /block-node/s3-archive/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.archive.s3.S3ArchivePlugin; 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | module org.hiero.block.node.archive.s3cloud { 6 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 7 | 8 | // export configuration classes to the config module and app 9 | exports org.hiero.block.node.archive.s3 to 10 | com.swirlds.config.impl, 11 | com.swirlds.config.extensions, 12 | org.hiero.block.node.app; 13 | 14 | requires transitive com.swirlds.config.api; 15 | requires transitive org.hiero.block.node.spi; 16 | requires com.hedera.pbj.runtime; 17 | requires org.hiero.block.common; 18 | requires org.hiero.block.node.base; 19 | requires org.hiero.block.protobuf.pbj; 20 | requires com.github.spotbugs.annotations; 21 | requires java.management; 22 | requires java.net.http; 23 | requires java.xml; 24 | 25 | provides org.hiero.block.node.spi.BlockNodePlugin with 26 | S3ArchivePlugin; 27 | } 28 | -------------------------------------------------------------------------------- /block-node/s3-archive/src/main/java/org/hiero/block/node/archive/s3/S3ArchiveConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.archive.s3; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import org.hiero.block.common.utils.Preconditions; 7 | import org.hiero.block.node.base.Loggable; 8 | 9 | /** 10 | * Configuration for the archive service. 11 | * 12 | * @param blocksPerFile The number of blocks to write to a single archive file. 13 | * @param endpointUrl The endpoint URL for the archive service, e.g. " 14 | * https://s3.amazonaws.com/". 15 | * @param bucketName The name of the bucket to store the archive files. 16 | * @param basePath The base path for the archive files within the bucket. 17 | * @param storageClass The storage class for uploaded blocks (e.g., STANDARD | REDUCED_REDUNDANCY | STANDARD_IA | 18 | * ONEZONE_IA | INTELLIGENT_TIERING | GLACIER | DEEP_ARCHIVE | OUTPOSTS | GLACIER_IR | SNOW | 19 | * EXPRESS_ONEZONE). 20 | * @param regionName The region name for the archive service (e.g., us-east-1). 21 | * @param accessKey The access key for the archive service. 22 | * @param secretKey The secret key for the archive service. 23 | */ 24 | @ConfigData("archive") 25 | public record S3ArchiveConfig( 26 | @Loggable @ConfigProperty(defaultValue = "100000") int blocksPerFile, 27 | @Loggable @ConfigProperty(defaultValue = "") String endpointUrl, 28 | @Loggable @ConfigProperty(defaultValue = "block-node-archive") String bucketName, 29 | @Loggable @ConfigProperty(defaultValue = "blocks") String basePath, 30 | @Loggable @ConfigProperty(defaultValue = "STANDARD") String storageClass, 31 | @Loggable @ConfigProperty(defaultValue = "us-east-1") String regionName, 32 | @ConfigProperty(defaultValue = "") String accessKey, 33 | @ConfigProperty(defaultValue = "") String secretKey) { 34 | /** 35 | * Constructor. 36 | */ 37 | public S3ArchiveConfig { 38 | Preconditions.requirePositivePowerOf10(blocksPerFile); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /block-node/server-status/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node - Block Node Server Status API Module" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("io.helidon.logging.jul") 13 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 14 | } 15 | 16 | testModuleInfo { 17 | requires("org.junit.jupiter.api") 18 | requires("org.hiero.block.node.app.test.fixtures") 19 | } 20 | -------------------------------------------------------------------------------- /block-node/server-status/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.server.status.ServerStatusServicePlugin; 3 | 4 | module org.hiero.block.node.server.status { 5 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 6 | 7 | requires transitive org.hiero.block.node.spi; 8 | requires transitive org.hiero.block.protobuf.pbj; 9 | requires com.hedera.pbj.runtime; 10 | requires com.swirlds.metrics.api; 11 | requires com.github.spotbugs.annotations; 12 | 13 | provides org.hiero.block.node.spi.BlockNodePlugin with 14 | ServerStatusServicePlugin; 15 | } 16 | -------------------------------------------------------------------------------- /block-node/spi/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node Plugin SPI" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("org.apache.logging.log4j.slf4j2.impl") 13 | runtimeOnly("io.helidon.logging.jul") 14 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 15 | } 16 | 17 | testModuleInfo { 18 | requires("org.junit.jupiter.api") 19 | requires("org.junit.jupiter.params") 20 | } 21 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | module org.hiero.block.node.spi { 3 | exports org.hiero.block.node.spi; 4 | exports org.hiero.block.node.spi.blockmessaging; 5 | exports org.hiero.block.node.spi.historicalblocks; 6 | exports org.hiero.block.node.spi.health; 7 | exports org.hiero.block.node.spi.threading; 8 | 9 | uses org.hiero.block.node.spi.blockmessaging.BlockMessagingFacility; 10 | uses org.hiero.block.node.spi.historicalblocks.BlockProviderPlugin; 11 | uses org.hiero.block.node.spi.BlockNodePlugin; 12 | 13 | requires transitive com.hedera.pbj.runtime; 14 | requires transitive com.swirlds.config.api; 15 | requires transitive com.swirlds.metrics.api; 16 | requires transitive org.hiero.block.protobuf.pbj; 17 | requires transitive io.helidon.webserver; 18 | requires com.github.luben.zstd_jni; 19 | requires static transitive com.github.spotbugs.annotations; 20 | requires static java.compiler; // javax.annotation.processing.Generated 21 | } 22 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/ServiceBuilder.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi; 3 | 4 | import com.hedera.pbj.runtime.grpc.ServiceInterface; 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | import io.helidon.webserver.http.HttpService; 7 | 8 | /** 9 | * ServiceBuilder is an interface that defines the contract for registering HTTP and gRPC services with the web server 10 | * during initialization. 11 | */ 12 | public interface ServiceBuilder { 13 | /** 14 | * Registers an HTTP service with the web server. 15 | * 16 | * @param path the path for the HTTP service 17 | * @param service the HTTP service to register 18 | */ 19 | void registerHttpService(String path, HttpService... service); 20 | 21 | /** 22 | * Registers a gRPC service with the web server. 23 | * 24 | * @param service the gRPC service to register 25 | */ 26 | void registerGrpcService(@NonNull ServiceInterface service); 27 | } 28 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/ServiceLoaderFunction.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi; 3 | 4 | import java.util.ServiceLoader; 5 | import java.util.stream.Stream; 6 | 7 | /** 8 | * The ServiceLoaderFunction class is used to load services using the Java ServiceLoader. Or alternatively a custom 9 | * implementation of when testing. 10 | */ 11 | public class ServiceLoaderFunction { 12 | /** 13 | * Load services of the given class. This method will use the Java ServiceLoader to load the services. Unless 14 | * overridden by a custom implementation. 15 | * 16 | * @param serviceClass the class of the service to load 17 | * @param the type of the service 18 | * @return a stream of services of the given class 19 | */ 20 | public Stream loadServices(Class serviceClass) { 21 | return ServiceLoader.load(serviceClass).stream().map(ServiceLoader.Provider::get); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/blockmessaging/BlockItemHandler.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi.blockmessaging; 3 | 4 | /** 5 | * Interface for handling block items. 6 | */ 7 | public interface BlockItemHandler { 8 | /** 9 | * Handle a list of block items. Always called on handler thread. Each registered handler will have its own virtual 10 | * thread. 11 | *

12 | * When you get block items they could be the start of a block, starting with a header or middle block items, or end 13 | * with a block proof. The first block items you as a listener receive could be any of these and might be in the 14 | * middle of a block. You may get a full complete block header to proof, or it is possible to get a half complete 15 | * block because the sender had an issue and could not send the rest of the block. So if you get a block header and 16 | * have not received the block proof, you should assume that the block is incomplete and throw away the data. 17 | * Hopefully you will get that block resent directly after or shortly later but that is not guaranteed. 18 | * 19 | * @param blockItems the immutable list of block items to handle 20 | */ 21 | void handleBlockItemsReceived(BlockItems blockItems); 22 | } 23 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/blockmessaging/BlockNotificationHandler.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi.blockmessaging; 3 | 4 | /** 5 | * Interface for handling block notifications. 6 | */ 7 | public interface BlockNotificationHandler { 8 | /** 9 | * Handle a block verification notification. Always called on handler thread. Each registered handler will have its 10 | * own virtual thread. 11 | * 12 | * @param notification the block verification notification to handle 13 | */ 14 | default void handleVerification(VerificationNotification notification) {} 15 | 16 | /** 17 | * Handle a block persisted notification. Always called on handler thread. Each registered handler will have its 18 | * own virtual thread. 19 | * 20 | * @param notification the block persisted notification to handle 21 | */ 22 | default void handlePersisted(PersistedNotification notification) {} 23 | } 24 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/blockmessaging/NoBackPressureBlockItemHandler.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi.blockmessaging; 3 | 4 | /** 5 | * This interface is used to handle block items without applying back pressure. If the handler can not keep up with the 6 | * incoming block items, it will receive a call on the {@link #onTooFarBehindError()} method. After that point the 7 | * handler will not get calls to {@link BlockItemHandler#handleBlockItemsReceived(BlockItems)} anymore. 8 | */ 9 | public interface NoBackPressureBlockItemHandler extends BlockItemHandler { 10 | /** 11 | * Called when the block item handler is too far behind the current block number. This can happen if the handler is 12 | * not able to process the block items fast enough. After this call, the handler will not receive any more block 13 | * items. 14 | */ 15 | void onTooFarBehindError(); 16 | } 17 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/blockmessaging/PersistedNotification.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi.blockmessaging; 3 | 4 | public record PersistedNotification(long startBlockNumber, long endBlockNumber, int blockProviderPriority) { 5 | /** 6 | * Constructor for PersistedNotification. Validates the start and end block numbers. 7 | * 8 | * @param startBlockNumber the starting block number 9 | * @param endBlockNumber the ending block number 10 | */ 11 | public PersistedNotification { 12 | if (startBlockNumber > endBlockNumber) { 13 | throw new IllegalArgumentException("startBlockNumber must be less than or equal to endBlockNumber"); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/blockmessaging/VerificationNotification.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi.blockmessaging; 3 | 4 | import com.hedera.pbj.runtime.io.buffer.Bytes; 5 | 6 | /** 7 | * Simple record for block verification notifications. 8 | * 9 | * @param success true if the block was verified successfully, false otherwise 10 | * @param blockNumber the block number this notification is for 11 | * @param blockHash the hash of the block, if the type is BLOCK_VERIFIED 12 | * @param block the block, if the type is BLOCK_VERIFIED 13 | */ 14 | public record VerificationNotification( 15 | boolean success, long blockNumber, Bytes blockHash, org.hiero.block.internal.BlockUnparsed block) {} 16 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/health/HealthFacility.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi.health; 3 | 4 | /** 5 | * The status service is used to get the current status of the block node. 6 | */ 7 | public interface HealthFacility { 8 | /** 9 | * The status of the block node. 10 | */ 11 | enum State { 12 | /** The block node is starting up. */ 13 | STARTING, 14 | /** The block node is running. */ 15 | RUNNING, 16 | /** The block node is shutting down. */ 17 | SHUTTING_DOWN, 18 | } 19 | 20 | /** 21 | * Use this method to get the current status of the block node. 22 | * 23 | * @return the current status of the block node 24 | */ 25 | State blockNodeState(); 26 | 27 | /** 28 | * Checks if the service is running. 29 | * 30 | * @return true if the service is running, false otherwise 31 | */ 32 | default boolean isRunning() { 33 | return blockNodeState() == State.RUNNING; 34 | } 35 | 36 | /** 37 | * Shutdown the block node. This method is called to start shutting down the block node. 38 | * 39 | * @param className the name of the class stopping the service, for tracing shutdown reason 40 | * @param reason the reason for shutting down the block node 41 | */ 42 | void shutdown(final String className, final String reason); 43 | } 44 | -------------------------------------------------------------------------------- /block-node/spi/src/main/java/org/hiero/block/node/spi/historicalblocks/HistoricalBlockFacility.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.spi.historicalblocks; 3 | 4 | import org.hiero.block.node.spi.BlockNodePlugin; 5 | 6 | /** 7 | * The HistoricalBlockFacility interface is used to provide access to historical blocks to the different parts of the 8 | * block node. The range from the oldest block to the newest block is an inclusive range. 9 | */ 10 | @SuppressWarnings("unused") 11 | public interface HistoricalBlockFacility extends BlockNodePlugin { 12 | 13 | /** 14 | * Use this method to get the block at the specified block number. 15 | * 16 | * @param blockNumber the block number 17 | * @return the block at the specified block number, null if the block is not available 18 | */ 19 | BlockAccessor block(long blockNumber); 20 | 21 | /** 22 | * Use this method to get the set of all blocks available in this block node. 23 | * 24 | * @return the set of all blocks available in this block node 25 | */ 26 | BlockRangeSet availableBlocks(); 27 | } 28 | -------------------------------------------------------------------------------- /block-node/stream-publisher/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node Blocks Publisher Service" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("org.apache.logging.log4j.slf4j2.impl") 13 | runtimeOnly("io.helidon.logging.jul") 14 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 15 | } 16 | 17 | testModuleInfo { 18 | requires("org.junit.jupiter.api") 19 | requires("org.junit.jupiter.params") 20 | requires("org.hiero.block.node.app.test.fixtures") 21 | requires("org.mockito") 22 | requires("org.mockito.junit.jupiter") 23 | } 24 | -------------------------------------------------------------------------------- /block-node/stream-publisher/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.stream.publisher.PublisherServicePlugin; 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | module org.hiero.block.node.stream.publisher { 6 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 7 | 8 | // export configuration classes to the config module and app 9 | exports org.hiero.block.node.stream.publisher to 10 | com.swirlds.config.impl, 11 | com.swirlds.config.extensions, 12 | org.hiero.block.node.app; 13 | 14 | requires transitive com.hedera.pbj.runtime; 15 | requires transitive com.swirlds.config.api; 16 | requires transitive com.swirlds.metrics.api; 17 | requires transitive org.hiero.block.node.spi; 18 | requires transitive org.hiero.block.protobuf.pbj; 19 | requires org.hiero.block.common; 20 | requires org.hiero.block.node.base; 21 | requires com.github.spotbugs.annotations; 22 | 23 | provides org.hiero.block.node.spi.BlockNodePlugin with 24 | PublisherServicePlugin; 25 | } 26 | -------------------------------------------------------------------------------- /block-node/stream-publisher/src/main/java/org/hiero/block/node/stream/publisher/PublisherConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.stream.publisher; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import com.swirlds.config.api.validation.annotation.Min; 7 | import java.util.Objects; 8 | import org.hiero.block.common.utils.Preconditions; 9 | import org.hiero.block.node.base.Loggable; 10 | 11 | /** 12 | * Use this configuration across the producer package 13 | * 14 | * @param type use a predefined type string to replace the producer component implementation. 15 | * Non-PRODUCTION values should only be used for troubleshooting and development purposes. 16 | */ 17 | @ConfigData("producer") 18 | public record PublisherConfig( 19 | @Loggable @ConfigProperty(defaultValue = "PRODUCTION") PublisherType type, 20 | @Loggable @ConfigProperty(defaultValue = "8000") @Min(2000) int timeoutThresholdMillis) { 21 | /** 22 | * The type of the publisher service to use - PRODUCTION or NO_OP. 23 | */ 24 | public enum PublisherType { 25 | /** 26 | * Production mode, which is the default. Sends all incoming block items to the block messaging service 27 | */ 28 | PRODUCTION, 29 | /** 30 | * No-op mode. Does not send any block items to the block messaging service. Just updates the metrics 31 | */ 32 | NO_OP, 33 | } 34 | 35 | /** 36 | * Constructs a new {@code PublisherConfig} instance with validation. 37 | */ 38 | public PublisherConfig { 39 | Objects.requireNonNull(type); 40 | Preconditions.requirePositive(timeoutThresholdMillis); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /block-node/stream-publisher/src/main/java/org/hiero/block/node/stream/publisher/UpdateCallback.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.stream.publisher; 3 | 4 | /** 5 | * Interface for handling updates from the sessions. 6 | */ 7 | public interface UpdateCallback { 8 | enum UpdateType { 9 | BLOCK_ITEMS_RECEIVED, 10 | START_BLOCK, 11 | END_BLOCK, 12 | WHOLE_BLOCK, 13 | SESSION_ADDED, 14 | SESSION_CLOSED, 15 | } 16 | 17 | /** 18 | * Called when the update happens. 19 | * 20 | * @param session the session that is calling update, null if not from a session 21 | * @param updateType the type of update 22 | * @param blockNumber the block number, Always the current block number of session issuing the update. 23 | */ 24 | void update(BlockStreamProducerSession session, UpdateType updateType, long blockNumber); 25 | } 26 | -------------------------------------------------------------------------------- /block-node/stream-subscriber/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node Subscriber Service" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("org.apache.logging.log4j.slf4j2.impl") 13 | runtimeOnly("io.helidon.logging.jul") 14 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 15 | } 16 | 17 | testModuleInfo { 18 | requires("org.junit.jupiter.api") 19 | requires("org.hiero.block.node.app.test.fixtures") 20 | requires("org.assertj.core") 21 | requires("org.mockito") 22 | requires("org.mockito.junit.jupiter") 23 | } 24 | -------------------------------------------------------------------------------- /block-node/stream-subscriber/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.stream.subscriber.SubscriberServicePlugin; 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | module org.hiero.block.node.stream.subscriber { 6 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 7 | 8 | // export configuration classes to the config module and app 9 | exports org.hiero.block.node.stream.subscriber to 10 | com.swirlds.config.impl, 11 | com.swirlds.config.extensions, 12 | org.hiero.block.node.app; 13 | 14 | requires transitive com.hedera.pbj.runtime; 15 | requires transitive com.swirlds.config.api; 16 | requires transitive org.hiero.block.node.spi; 17 | requires transitive org.hiero.block.protobuf.pbj; 18 | requires com.swirlds.metrics.api; 19 | requires org.hiero.block.node.base; 20 | requires com.github.spotbugs.annotations; 21 | 22 | provides org.hiero.block.node.spi.BlockNodePlugin with 23 | SubscriberServicePlugin; 24 | } 25 | -------------------------------------------------------------------------------- /block-node/stream-subscriber/src/main/java/org/hiero/block/node/stream/subscriber/SubscriberConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.stream.subscriber; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import com.swirlds.config.api.validation.annotation.Min; 7 | import org.hiero.block.node.base.Loggable; 8 | 9 | /** 10 | * Use this configuration across the stream subscriber plugin. 11 | * 12 | * @param liveQueueSize The size of the queue used to transfer live batches 13 | * between the messaging and the client thread.
14 | * This value is a number of _batches_, not blocks, so generally this should 15 | * be around 100 times the number of blocks that should be pending at any 16 | * moment (i.e. a typical block is 100 batches, so to support 50 blocks this 17 | * value would be 5000). 18 | * @param maximumFutureRequest The furthest in the future a request can set the 19 | * start block for a stream. If a request specifies a start block further 20 | * than this many blocks above the latest known "live" block, the request will 21 | * be rejected. 22 | * @param minimumLiveQueueCapacity The minimum available capacity in the live queue 23 | * that the session will try to maintain. If there is less than this much 24 | * capacity available, the session will drop the oldest full blocks (at the queue head) 25 | * in the queue until at least this many batches can be added without blocking.
26 | * This value should typically be around 10% of the live queue size. 27 | */ 28 | @ConfigData("subscriber") 29 | public record SubscriberConfig( 30 | @Loggable @ConfigProperty(defaultValue = "4000") @Min(100) int liveQueueSize, 31 | @Loggable @ConfigProperty(defaultValue = "4000") @Min(10) long maximumFutureRequest, 32 | @Loggable @ConfigProperty(defaultValue = "400") @Min(10) int minimumLiveQueueCapacity) {} 33 | -------------------------------------------------------------------------------- /block-node/verification/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node Verification Service" 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | mainModuleInfo { 11 | runtimeOnly("com.swirlds.config.impl") 12 | runtimeOnly("org.apache.logging.log4j.slf4j2.impl") 13 | runtimeOnly("io.helidon.logging.jul") 14 | runtimeOnly("com.hedera.pbj.grpc.helidon.config") 15 | } 16 | 17 | testModuleInfo { 18 | requires("org.junit.jupiter.api") 19 | requires("org.hiero.block.node.app.test.fixtures") 20 | requires("org.mockito") 21 | } 22 | -------------------------------------------------------------------------------- /block-node/verification/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.node.verification.VerificationServicePlugin; 3 | 4 | // SPDX-License-Identifier: Apache-2.0 5 | module org.hiero.block.node.verification { 6 | uses com.swirlds.config.api.spi.ConfigurationBuilderFactory; 7 | 8 | // export configuration classes to the config module and app 9 | exports org.hiero.block.node.verification to 10 | com.swirlds.config.impl, 11 | com.swirlds.config.extensions, 12 | org.hiero.block.node.app; 13 | 14 | requires transitive com.hedera.pbj.runtime; 15 | requires transitive com.swirlds.config.api; 16 | requires transitive org.hiero.block.common; 17 | requires transitive org.hiero.block.node.spi; 18 | requires transitive org.hiero.block.protobuf.pbj; 19 | requires com.swirlds.metrics.api; 20 | requires org.hiero.block.node.base; 21 | requires com.github.spotbugs.annotations; 22 | 23 | provides org.hiero.block.node.spi.BlockNodePlugin with 24 | VerificationServicePlugin; 25 | } 26 | -------------------------------------------------------------------------------- /block-node/verification/src/main/java/org/hiero/block/node/verification/VerificationConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.node.verification; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import org.hiero.block.common.utils.Preconditions; 7 | import org.hiero.block.node.base.Loggable; 8 | 9 | /** 10 | * Configuration for the verification module. 11 | * 12 | * @param type toggle between production and no-op verification services 13 | * @param hashCombineBatchSize the size of the batch used to combine hashes 14 | */ 15 | @ConfigData("verification") 16 | public record VerificationConfig( 17 | @Loggable @ConfigProperty(defaultValue = "PRODUCTION") VerificationServiceType type, 18 | @Loggable @ConfigProperty(defaultValue = "32") int hashCombineBatchSize) { 19 | 20 | /** 21 | * Constructs a new instance of {@link VerificationConfig}. 22 | * 23 | * @param type toggle between PRODUCTION and NO_OP verification services 24 | * @param hashCombineBatchSize the size of the batch used to combine hashes 25 | */ 26 | public VerificationConfig { 27 | // hashCombineBatchSize must be even and greater than 2 28 | Preconditions.requirePositive(hashCombineBatchSize, "[VERIFICATION_HASH_COMBINE_BATCH_SIZE] must be positive"); 29 | Preconditions.requireEven( 30 | hashCombineBatchSize, "[VERIFICATION_HASH_COMBINE_BATCH_SIZE] must be even and greater than 2"); 31 | } 32 | 33 | /** 34 | * The type of the verification service to use - PRODUCTION or NO_OP. 35 | */ 36 | public enum VerificationServiceType { 37 | PRODUCTION, 38 | NO_OP, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import net.swiftzer.semver.SemVer 3 | 4 | tasks.versionAsSpecified { 5 | val chartFiles = 6 | fileTree(rootDir) { 7 | include("charts/**/Chart.yaml") 8 | exclude("**/node_modules/") 9 | } 10 | doLast { 11 | val newVersion = SemVer.parse(inputs.properties["newVersion"] as String).toString() 12 | chartFiles.forEach { file -> 13 | val yaml = file.readText() 14 | val oldVersion = Regex("(?<=^(appVersion|version): ).+", RegexOption.MULTILINE) 15 | file.writeText(yaml.replace(oldVersion, newVersion)) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /charts/.gitignore: -------------------------------------------------------------------------------- 1 | */out 2 | out 3 | /hedera-block-node/Chart.lock 4 | /hedera-block-node/charts/* 5 | */charts/*.tgz 6 | *.lock 7 | -------------------------------------------------------------------------------- /charts/block-node-server/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/block-node-server/Chart.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | apiVersion: v2 3 | appVersion: 0.14.0-SNAPSHOT 4 | description: A Helm chart for Hiero Block Node 5 | home: https://github.com/hiero-ledger/hiero-block-node 6 | keywords: 7 | - blocknode 8 | - dlt 9 | - hiero 10 | - hedera 11 | - hashgraph 12 | maintainers: 13 | - name: Hiero Block Node Team 14 | email: blocknode@hashgraph.com 15 | name: block-node-helm-chart 16 | sources: 17 | - https://github.com/hiero-ledger/hiero-block-node 18 | version: 0.14.0-SNAPSHOT 19 | dependencies: 20 | - name: kube-prometheus-stack 21 | alias: kubepromstack 22 | condition: kubepromstack.enabled 23 | version: "51.2.0" # Use the latest stable version 24 | repository: "https://prometheus-community.github.io/helm-charts" 25 | - name: "loki" 26 | condition: loki.enabled 27 | repository: "https://grafana.github.io/helm-charts" 28 | version: "^2.15.2" 29 | - name: "promtail" 30 | condition: promtail.enabled 31 | repository: "https://grafana.github.io/helm-charts" 32 | version: "^6.7.4" 33 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. **Get the application URL** by running the following commands: 2 | 3 | ```bash 4 | kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{.Release.Name}}-{{.Chart.Name}} 8080:{{ .Values.service.port }} 5 | echo "Visit http://127.0.0.1:8080 to use your application" 6 | ``` 7 | 8 | {{- if .Values.kubepromstack.enabled }} 9 | 10 | 11 | 2. **Access Grafana** by mapping the service port: 12 | 13 | ```bash 14 | kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{.Release.Name}}-grafana 3000:80 15 | echo "Grafana is accessible at http://localhost:3000" 16 | ``` 17 | 18 | **Note**: This command forwards your local port `3000` to Grafana's port `80`. Ensure that port `3000` is free on your local machine or choose another available port if necessary. 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/configmap-logging.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ include "hiero-block-node.fullname" . }}-logging-config 5 | data: 6 | logging.properties: | 7 | # Log properties 8 | .level= {{ .Values.blockNode.logs.level }} 9 | 10 | {{- range $key, $value := .Values.blockNode.logs.loggingProperties }} 11 | {{ $key }}={{ $value }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */}} 4 | 5 | apiVersion: v1 6 | kind: ConfigMap 7 | metadata: 8 | name: {{ include "hiero-block-node.fullname" . }}-config 9 | data: 10 | VERSION: {{ include "hiero-block-node.appVersion" . | quote }} 11 | {{- range $key, $value := .Values.blockNode.config }} 12 | {{ $key }}: {{ $value | quote }} 13 | {{- end }} 14 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/grafana-dashboard-configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */}} 4 | 5 | {{ if .Values.kubepromstack.enabled }} 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | name: block-node-dashboard-configmap 10 | labels: 11 | grafana_dashboard: "1" 12 | data: 13 | block-node-dashboard.json: {{ .Files.Get "dashboards/block-node-server.json" | quote }} 14 | node-exporter-dashboard.json: {{ .Files.Get "dashboards/node-exporter-full.json" | quote }} 15 | kubernetes-views-pods.json : {{ .Files.Get "dashboards/kubernetes-views-pods.json" | quote }} 16 | 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/grafana-datasource.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */}} 4 | 5 | {{ if .Values.kubepromstack.enabled }} 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | name: {{ include "hiero-block-node.fullname" . }}-grafana-datasource 10 | labels: 11 | grafana_datasource: "1" 12 | data: 13 | datasource.yaml: | 14 | apiVersion: 2 15 | datasources: 16 | - name: Prometheus 17 | type: prometheus 18 | access: proxy 19 | url: http://{{ .Release.Name }}-kubepromstack-prometheus:9090 20 | isDefault: true 21 | editable: true 22 | jsonData: 23 | timeInterval: "15s" 24 | 25 | {{- if .Values.loki.enabled }} 26 | - name: Loki 27 | type: loki 28 | url: http://{{ .Release.Name }}-loki:3100 29 | access: proxy 30 | isDefault: false 31 | editable: true 32 | {{- end }} 33 | 34 | {{- end }} 35 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/pvc-archive.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.blockNode.persistence.archive.create }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: {{ include "hiero-block-node.fullname" . }}-archive 6 | labels: 7 | {{- include "hiero-block-node.labels" . | nindent 4 }} 8 | spec: 9 | accessModes: 10 | - ReadWriteOnce 11 | resources: 12 | requests: 13 | storage: {{ .Values.blockNode.persistence.archive.size }} 14 | {{- if .Values.blockNode.persistence.archive.storageClass }} 15 | storageClassName: {{ .Values.blockNode.persistence.archive.storageClass }} 16 | {{- end }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/pvc-live.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.blockNode.persistence.live.create }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: {{ include "hiero-block-node.fullname" . }}-live 6 | labels: 7 | {{- include "hiero-block-node.labels" . | nindent 4 }} 8 | spec: 9 | accessModes: 10 | - ReadWriteOnce 11 | resources: 12 | requests: 13 | storage: {{ .Values.blockNode.persistence.live.size }} 14 | {{- if .Values.blockNode.persistence.live.storageClass }} 15 | storageClassName: {{ .Values.blockNode.persistence.live.storageClass }} 16 | {{- end }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/pvc-logging.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.blockNode.persistence.logging.create }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: {{ include "hiero-block-node.fullname" . }}-logging 6 | labels: 7 | {{- include "hiero-block-node.labels" . | nindent 4 }} 8 | spec: 9 | accessModes: 10 | - ReadWriteOnce 11 | resources: 12 | requests: 13 | storage: {{ .Values.blockNode.persistence.logging.size }} 14 | {{- if .Values.blockNode.persistence.logging.storageClass }} 15 | storageClassName: {{ .Values.blockNode.persistence.logging.storageClass }} 16 | {{- end }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.blockNode.secret }} 2 | {{- /* 3 | SPDX-License-Identifier: Apache-2.0 4 | */}} 5 | 6 | apiVersion: v1 7 | kind: Secret 8 | metadata: 9 | name: {{ include "hiero-block-node.fullname" . }}-secret 10 | type: Opaque 11 | data: 12 | {{- range $key, $value := .Values.blockNode.secret }} 13 | {{ $key }}: {{ $value | b64enc }} 14 | {{- end }} 15 | {{- end}} 16 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */}} 4 | 5 | apiVersion: v1 6 | kind: Service 7 | metadata: 8 | name: {{ include "hiero-block-node.fullname" . }} 9 | labels: 10 | app: {{ include "hiero-block-node.name" . }} 11 | {{- include "hiero-block-node.labels" . | nindent 4 }} 12 | spec: 13 | type: {{ .Values.service.type }} 14 | ports: 15 | - port: {{ .Values.service.port }} 16 | targetPort: http 17 | protocol: TCP 18 | name: http 19 | - name: metrics 20 | port: {{ .Values.blockNode.health.metrics.port }} 21 | targetPort: metrics 22 | selector: 23 | {{- include "hiero-block-node.selectorLabels" . | nindent 4 }} 24 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */}} 4 | 5 | {{- if .Values.serviceAccount.create -}} 6 | apiVersion: v1 7 | kind: ServiceAccount 8 | metadata: 9 | name: {{ include "hiero-block-node.serviceAccountName" . }} 10 | labels: 11 | {{- include "hiero-block-node.labels" . | nindent 4 }} 12 | {{- with .Values.serviceAccount.annotations }} 13 | annotations: 14 | {{- toYaml . | nindent 4 }} 15 | {{- end }} 16 | {{- end }} 17 | -------------------------------------------------------------------------------- /charts/block-node-server/templates/servicemonitor.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */}} 4 | 5 | {{ if .Values.kubepromstack.enabled }} 6 | apiVersion: monitoring.coreos.com/v1 7 | kind: ServiceMonitor 8 | metadata: 9 | name: {{ include "hiero-block-node.fullname" . }} 10 | labels: 11 | app: {{ include "hiero-block-node.name" . }} 12 | release: {{ .Release.Name }} 13 | {{- include "hiero-block-node.labels" . | nindent 4 }} 14 | spec: 15 | selector: 16 | matchLabels: 17 | app: {{ include "hiero-block-node.name" . }} 18 | namespaceSelector: 19 | matchNames: 20 | - {{ .Release.Namespace }} 21 | endpoints: 22 | - port: metrics 23 | interval: 15s 24 | 25 | {{- end }} 26 | -------------------------------------------------------------------------------- /charts/block-node-server/values-overrides/mid-size.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | requests: 3 | cpu: "4" 4 | memory: "12Gi" 5 | -------------------------------------------------------------------------------- /charts/block-node-server/values-overrides/mini.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # This override values for the block-node-server chart to deploy a mini version of the block-node-server. 4 | # This is useful for testing and development purposes with limited resources. 5 | # ie: minikube 6 | 7 | resources: 8 | requests: 9 | cpu: "3" 10 | memory: "8Gi" 11 | 12 | blockNode: 13 | config: 14 | JAVA_OPTS: "-Xms5G -Xmx5G" 15 | MEDIATOR_RING_BUFFER_SIZE: "2048" 16 | persistence: 17 | archive: 18 | size: 6Gi 19 | live: 20 | size: 1Gi 21 | logging: 22 | size: 1Gi 23 | 24 | # Setting the PVC size for the Observability stack to mini claims of 1 Gigabyte 25 | kubepromstack: 26 | prometheus: 27 | prometheusSpec: 28 | storageSpec: 29 | volumeClaimTemplate: 30 | spec: 31 | resources: 32 | requests: 33 | storage: 1Gi 34 | grafana: 35 | persistence: 36 | size: 1Gi 37 | 38 | loki: 39 | persistence: 40 | size: 1Gi 41 | -------------------------------------------------------------------------------- /charts/blockstream-simulator/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/blockstream-simulator/Chart.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | apiVersion: v2 3 | appVersion: 0.14.0-SNAPSHOT 4 | description: A Helm chart for Hiero Blockstream Simulator. 5 | home: https://github.com/hiero-ledger/hiero-block-node 6 | keywords: 7 | - blocknode 8 | - dlt 9 | - hiero 10 | - hedera 11 | - hashgraph 12 | - blockstream 13 | - simulator 14 | maintainers: 15 | - name: Hiero Block Node Team 16 | email: blocknode@hashgraph.com 17 | name: blockstream-simulator-chart 18 | sources: 19 | - https://github.com/hiero-ledger/hiero-block-node 20 | version: 0.14.0-SNAPSHOT 21 | -------------------------------------------------------------------------------- /charts/blockstream-simulator/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | BlockStream Simulator Chart has been deployed successfully. 2 | The simulator does not expose any services or API, but it automatically starts to work with the provided documentation. 3 | 4 | The configuration can be overridden by providing a custom values.yaml with the following dictionary: 5 | simulator.config 6 | -------------------------------------------------------------------------------- /charts/blockstream-simulator/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */}} 4 | 5 | apiVersion: v1 6 | kind: ConfigMap 7 | metadata: 8 | name: {{ include "blockstream-simulator-chart.fullname" . }}-config 9 | data: 10 | {{- range $key, $value := .Values.simulator.config }} 11 | {{ $key }}: {{ $value | quote }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /charts/blockstream-simulator/templates/pvc-simulator-data.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.simulator.persistence.data.create }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: {{ include "blockstream-simulator-chart.fullname" . }}-data 6 | labels: 7 | {{- include "blockstream-simulator-chart.labels" . | nindent 4 }} 8 | spec: 9 | accessModes: 10 | - ReadWriteOnce 11 | resources: 12 | requests: 13 | storage: {{ .Values.simulator.persistence.data.size }} 14 | {{- if .Values.simulator.persistence.data.storageClass }} 15 | storageClassName: {{ .Values.simulator.persistence.data.storageClass }} 16 | {{- end }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/blockstream-simulator/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | SPDX-License-Identifier: Apache-2.0 3 | */}} 4 | 5 | apiVersion: v1 6 | kind: Secret 7 | metadata: 8 | name: {{ include "blockstream-simulator-chart.fullname" . }}-secret 9 | type: Opaque 10 | data: 11 | {{- range $key, $value := .Values.simulator.secret }} 12 | {{ $key }}: {{ $value | b64enc }} 13 | {{- end }} 14 | -------------------------------------------------------------------------------- /charts/blockstream-simulator/values-overrides/consumer.yaml: -------------------------------------------------------------------------------- 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" 8 | SIMULATOR_STARTUP_DATA_ENABLED: "false" 9 | -------------------------------------------------------------------------------- /charts/blockstream-simulator/values.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | image: 3 | repository: ghcr.io/hiero-ledger/hiero-block-node/simulator-image 4 | pullPolicy: IfNotPresent 5 | # Overrides the image tag whose default is the chart appVersion. 6 | tag: "" 7 | 8 | imagePullSecrets: [] 9 | nameOverride: "" 10 | fullnameOverride: "" 11 | podAnnotations: {} 12 | podSecurityContext: {} 13 | securityContext: {} 14 | resources: {} 15 | nodeSelector: {} 16 | tolerations: [] 17 | affinity: {} 18 | 19 | replicas: 1 20 | 21 | simulator: 22 | config: 23 | # either CONSUMER or PUBLISHER 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 31 | SIMULATOR_STARTUP_DATA_ENABLED: "true" 32 | secret: 33 | PRIVATE_KEY: "fake_private_key" 34 | persistence: 35 | data: 36 | # If false, the chart expects an externally provided PVC 37 | create: true 38 | # Name of the externally provided PVC 39 | existingClaim: "" 40 | # Name of the subPath in the PVC to mount to mountPath in the container 41 | subPath: "simulator-data" 42 | # If create is true, the following values are used to create the PVC 43 | mountPath: "/opt/simulator/data" 44 | size: 1Gi 45 | # Optionally add a storage class name if needed 46 | # storageClass: "your-storage-class" 47 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | max_report_age: off 3 | 4 | # Only comment on PRs initially and when coverage changes 5 | comment: 6 | layout: "diff, flags, files" 7 | behavior: new # deletes old comment and posts a new one 8 | require_changes: true 9 | 10 | coverage: 11 | status: 12 | patch: 13 | default: 14 | target: 80% 15 | threshold: 1% 16 | only_pulls: true 17 | project: 18 | default: 19 | target: 80% 20 | threshold: 1% 21 | branches: 22 | - main 23 | 24 | ignore: 25 | - "simulator/src/main/java/org/hiero/block/simulator/BlockStreamSimulator.java" 26 | - "tools-and-tests/tools/**" 27 | - "tools-and-tests/suites/**" 28 | - "**/src/test/**" 29 | - "block-node/app/src/testFixtures/**" 30 | -------------------------------------------------------------------------------- /common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Commons module with logic that could be abstracted and reused." 5 | 6 | // Remove the following line to enable all 'javac' lint checks that we have turned on by default 7 | // and then fix the reported issues. 8 | tasks.withType().configureEach { options.compilerArgs.add("-Xlint:-exports") } 9 | 10 | testModuleInfo { 11 | requiresStatic("com.github.spotbugs.annotations") 12 | requires("org.junit.jupiter.api") 13 | requires("org.junit.jupiter.params") 14 | requires("org.assertj.core") 15 | requires("com.google.common.jimfs") 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | module org.hiero.block.common { 3 | exports org.hiero.block.common.constants; 4 | exports org.hiero.block.common.utils; 5 | exports org.hiero.block.common.hasher; 6 | 7 | requires transitive com.hedera.pbj.runtime; 8 | requires transitive org.hiero.block.protobuf.pbj; 9 | requires com.swirlds.common; 10 | requires static com.github.spotbugs.annotations; 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/org/hiero/block/common/constants/StringsConstants.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.common.constants; 3 | 4 | /** A class that hold common String literals used across projects. */ 5 | public final class StringsConstants { 6 | /** 7 | * File name for application properties 8 | */ 9 | public static final String APPLICATION_PROPERTIES = "app.properties"; 10 | 11 | /** 12 | * File name for application test properties (may override APPLICATION_PROPERTIES) 13 | */ 14 | public static final String APPLICATION_TEST_PROPERTIES = "app-test.properties"; 15 | 16 | /** 17 | * File name for logging properties 18 | */ 19 | public static final String LOGGING_PROPERTIES = "logging.properties"; 20 | 21 | private StringsConstants() {} 22 | } 23 | -------------------------------------------------------------------------------- /common/src/main/java/org/hiero/block/common/hasher/Hashes.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.common.hasher; 3 | 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | import java.nio.ByteBuffer; 6 | 7 | /** 8 | * Holds the input and output hashes of a list of block items. 9 | * 10 | * @param inputHashes the input hashes 11 | * @param outputHashes the output hashes 12 | */ 13 | public record Hashes(@NonNull ByteBuffer inputHashes, @NonNull ByteBuffer outputHashes) {} 14 | -------------------------------------------------------------------------------- /common/src/main/java/org/hiero/block/common/utils/ChunkUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.common.utils; 3 | 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.Objects; 10 | 11 | /** Utility class for chunking collections. */ 12 | public final class ChunkUtils { 13 | /** 14 | * Chunk a collection into a list of lists. 15 | * The resulting list will have a specified size. 16 | * 17 | * @param dataToSplit the collection to chunk, if the collection is empty, an empty list is returned. 18 | * @param chunkSize the size of each chunk 19 | * @param the type of the collection 20 | * @return a list of lists of the specified size 21 | * */ 22 | public static List> chunkify(@NonNull final Collection dataToSplit, final int chunkSize) { 23 | Objects.requireNonNull(dataToSplit); 24 | if (chunkSize <= 0) { 25 | throw new IllegalArgumentException("Chunk size must be greater than 0"); 26 | } 27 | if (dataToSplit.isEmpty()) { 28 | return Collections.emptyList(); // or throw, depends on how we want to handle 29 | } 30 | final List localCollection = List.copyOf(dataToSplit); 31 | final int localCollectionSize = localCollection.size(); 32 | 33 | List> result = new ArrayList<>(); 34 | 35 | for (int i = 0; i < localCollectionSize; i += chunkSize) { 36 | int end = Math.min(i + chunkSize, localCollectionSize); 37 | result.add(localCollection.subList(i, end)); 38 | } 39 | 40 | return result; 41 | } 42 | 43 | private ChunkUtils() {} 44 | } 45 | -------------------------------------------------------------------------------- /common/src/main/java/org/hiero/block/common/utils/StringUtilities.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.common.utils; 3 | 4 | import java.util.Objects; 5 | 6 | /** A utility class that deals with logic related to Strings. */ 7 | public final class StringUtilities { 8 | /** Empty {@link String} constant. Non-null, but with no whitespaces. */ 9 | public static final String EMPTY = ""; 10 | 11 | /** 12 | * This method takes an input {@link String} and checks if it is blank. 13 | * A {@link String} is considered blank if it is either {@code null} or 14 | * contains only whitespace characters as defined by 15 | * {@link String#isBlank()}. 16 | * 17 | * @param toCheck a {@link String} to check if it is blank 18 | * @return {@code true} if the given {@link String} to check is either 19 | * {@code null} or contains only whitespace characters, {@code false} 20 | * otherwise 21 | */ 22 | public static boolean isBlank(final String toCheck) { 23 | return Objects.isNull(toCheck) || toCheck.isBlank(); 24 | } 25 | 26 | private StringUtilities() {} 27 | } 28 | -------------------------------------------------------------------------------- /common/src/test/java/org/hiero/block/common/utils/StringUtilitiesTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.common.utils; 3 | 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import org.junit.jupiter.params.ParameterizedTest; 7 | import org.junit.jupiter.params.provider.MethodSource; 8 | 9 | /** 10 | * Tests for {@link StringUtilities} functionality. 11 | */ 12 | class StringUtilitiesTest { 13 | /** 14 | * This test aims to verify that the {@link StringUtilities#isBlank(String)} 15 | * returns {@code true} if the input string is blank. 16 | * 17 | * @param toTest parameterized, the String to test 18 | */ 19 | @ParameterizedTest 20 | @MethodSource("org.hiero.block.common.CommonsTestUtility#blankStrings") 21 | void testRequireNotBlankPass(final String toTest) { 22 | assertThat(StringUtilities.isBlank(toTest)).isTrue(); 23 | } 24 | 25 | /** 26 | * This test aims to verify that the {@link StringUtilities#isBlank(String)} 27 | * returns {@code false} if the input string is not blank. 28 | * 29 | * @param toTest parameterized, the string to test 30 | */ 31 | @ParameterizedTest 32 | @MethodSource("org.hiero.block.common.CommonsTestUtility#nonBlankStrings") 33 | void testRequireNotBlankFail(final String toTest) { 34 | assertThat(StringUtilities.isBlank(toTest)).isFalse(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common/src/test/resources/invalid1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/common/src/test/resources/invalid1.gz -------------------------------------------------------------------------------- /common/src/test/resources/valid1.blk: -------------------------------------------------------------------------------- 1 | valid1blk -------------------------------------------------------------------------------- /common/src/test/resources/valid1.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/common/src/test/resources/valid1.txt.gz -------------------------------------------------------------------------------- /common/src/test/resources/valid2.blk: -------------------------------------------------------------------------------- 1 | valid2blk -------------------------------------------------------------------------------- /common/src/test/resources/valid2.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/common/src/test/resources/valid2.txt.gz -------------------------------------------------------------------------------- /ct.yaml: -------------------------------------------------------------------------------- 1 | check-version-increment: false 2 | target-branch: main 3 | validate-maintainers: false 4 | install: 5 | timeout: 600 6 | -------------------------------------------------------------------------------- /docs/assets/00036-consumer-registration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/docs/assets/00036-consumer-registration.png -------------------------------------------------------------------------------- /docs/assets/00036-demo-disruptor-class-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/docs/assets/00036-demo-disruptor-class-diagram.png -------------------------------------------------------------------------------- /docs/assets/00036-producer-registration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/docs/assets/00036-producer-registration.png -------------------------------------------------------------------------------- /docs/assets/00036-refactor-demo-disruptor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/docs/assets/00036-refactor-demo-disruptor.png -------------------------------------------------------------------------------- /docs/block-node/README.md: -------------------------------------------------------------------------------- 1 | # Server 2 | 3 | The Block Node Server Application is designed to handle the block streams output of a Hiero Node, parsing and storing 4 | the blocks and network state information. It will also optionally provide many value adding APIs to allow downstream 5 | applications to access block and state information. 6 | 7 | 8 | 9 | ## Configuration 10 | 11 | Refer to the [Configuration](configuration.md) for configuration options. 12 | 13 | ## Quickstart 14 | 15 | Refer to the [Quickstart](quickstart.md) for a quick guide on how to get started with the application. 16 | -------------------------------------------------------------------------------- /docs/block-node/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart of the Server 2 | 3 | ## Table of Contents 4 | 5 | 1. [Configuration](#configuration) 6 | 2. [Running locally](#running-locally) 7 | 1. [Build the Server](#build-the-server) 8 | 2. [Run the Server](#run-the-server) 9 | 3. [Run the Server with Debug](#run-the-server-with-debug) 10 | 4. [Stop the Server](#stop-the-server) 11 | 12 | ## Configuration 13 | 14 | Refer to the [Configuration](../configuration.md) for configuration options. 15 | 16 | ## Running locally 17 | 18 | - Server subproject qualifier: `:block-node:app` 19 | - Assuming your working directory is the repo root 20 | 21 | > **NOTE:** one may use the `-p` flag for `./gradlew` in order to avoid 22 | > specifying the target subproject repeatedly on each task when running 23 | > multiple tasks. When running only a single task, however, it is 24 | > recommended to use the project qualifier (i.e. `:block-node:app:`) for 25 | > both simplicity and clarity. 26 | 27 | ### Build the Server 28 | 29 | > **NOTE:** if you have not done so already, it is 30 | > generally recommended to build the entire repo first: 31 | > 32 | > ```bash 33 | > ./gradlew clean build -x test 34 | > ``` 35 | 36 | 1. To quickly build the Server sources (without running tests), do the following: 37 | 38 | ```bash 39 | ./gradlew clean build -x test 40 | ``` 41 | 2. Before building the server ensure your tests run successfully: 42 | 43 | ```bash 44 | ./gradlew clean qualityGate build runSuites 45 | ``` 46 | 3. To build the Server docker image, do the following: 47 | 48 | ```bash 49 | ./gradlew :block-node-app:createDockerImage 50 | ``` 51 | 52 | ### Run the Server 53 | 54 | 1. To start the Server, do the following: 55 | 56 | ```bash 57 | ./gradlew :block-node-app:startDockerContainer 58 | ``` 59 | 60 | ### Run the Server with Debug 61 | 62 | 1. To start the Server with debug enabled, do the following: 63 | 64 | ```bash 65 | ./gradlew :block-node-app:startDockerDebugContainer 66 | ``` 67 | 2. Attach your remote jvm debugger to port 5005. 68 | 69 | ### Stop the Server 70 | 71 | 1. To stop the Server do the following: 72 | 73 | ```bash 74 | ./gradlew :block-node-app:stopDockerContainer 75 | ``` 76 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | The Hiero Block Node repo is composed of multiple components that can be configured using the following options: 4 | 5 | ## Default Configuration 6 | 7 | The default configuration allows users to quickly get up and running without having to configure anything. This provides 8 | ease of use at the trade-off of some insecure default configuration. Most configuration settings have appropriate 9 | defaults and can be left unchanged. It is recommended to browse the properties below and adjust to your needs. 10 | 11 | The configuration facility of the Hiero Block Node supports overriding configuration values via environment variables, 12 | with a well-defined transform from property name to environment variable name. 13 | 14 | > **Note:** The default configuration should be considered a "production" recommendation, and we may provide separate 15 | > recommended "overrides" for development, test, etc... 16 | 17 | ## Server 18 | 19 | Server configuration options are described at [Server Configuration](block-node/configuration.md). 20 | 21 | ## Simulator 22 | 23 | Simulator configuration options are described at [Simulator Configuration](simulator/configuration.md). 24 | -------------------------------------------------------------------------------- /docs/design/communication-protocol/README.md: -------------------------------------------------------------------------------- 1 | # Protocol Documents 2 | 3 | This folder contains documents describing the expected protocol for various 4 | APIs provided by the Block Node and related systems. 5 | Each protocol document should describe a single API call and the expected 6 | behavior of both sides of that API call, including common error conditions. 7 | 8 | ## Contents 9 | 10 | | Document | API call | Description | 11 | |:-------------------------------------------------|---------------------:|:---------------------------------------------------------------------------------------------------------------------------------------------| 12 | | [publishBlockStream.md](publish-block-stream.md) | `publishBlockStream` | The communication between a publisher and a Block Node when publishing a Block Stream from an authoritative source such as a Consensus Node. | 13 | -------------------------------------------------------------------------------- /docs/design/design-doc-template.md: -------------------------------------------------------------------------------- 1 | # Design Document Template 2 | 3 | ## Table of Contents 4 | 5 | 1. [Purpose](#purpose) 6 | 2. [Goals](#goals) 7 | 3. [Terms](#terms) 8 | 4. [Entities](#entities) 9 | 5. [Design](#design) 10 | 6. [Diagram](#diagram) 11 | 7. [Configuration](#configuration) 12 | 8. [Metrics](#metrics) 13 | 9. [Exceptions](#exceptions) 14 | 10. [Acceptance Tests](#acceptance-tests) 15 | 16 | ## Purpose 17 | 18 | ## Goals 19 | 20 | ## Terms 21 | 22 |

23 |
Term
24 |
A Term is any word or short phrase used in this document that 25 | requires clear definition and/or explanation.
26 |
27 | 28 | ## Entities 29 | 30 | ## Design 31 | 32 | ## Diagram 33 | 34 | Consider using mermaid to generate one or more of the following: 35 | - [User Journey](https://mermaid.js.org/syntax/userJourney.html) 36 | - [Requirement Diagram](https://mermaid.js.org/syntax/requirementDiagram.html) 37 | - [Sequence Diagram](https://mermaid.js.org/syntax/sequenceDiagram.html) 38 | - [Class Diagram](https://mermaid.js.org/syntax/classDiagram.html) 39 | - [Block Diagram](https://mermaid.js.org/syntax/block.html) 40 | - [Architecture Diagram](https://mermaid.js.org/syntax/architecture.html) 41 | - [Flowchart](https://mermaid.js.org/syntax/flowchart.html) 42 | - [State Diagram](https://mermaid.js.org/syntax/stateDiagram.html) 43 | - [Entity Relationship Diagram](https://mermaid.js.org/syntax/entityRelationshipDiagram.html)** 44 | 45 | ## Configuration 46 | 47 | ## Metrics 48 | 49 | ## Exceptions 50 | 51 | ## Acceptance Tests 52 | -------------------------------------------------------------------------------- /docs/design/how-to-design-doc.md: -------------------------------------------------------------------------------- 1 | # How to start a design doc 2 | 3 | 1) Copy the [template](../../../../docs/design/design-doc-template.mdn/design-doc-template.md) from `docs/design/design-doc-template.md` to a new markdown file. 4 | 2) Take a look at [this example](../../block-node/server/docs/design/block-verification.md) `docs/design/block-verification.md` for the detail level and tone. 5 | 3) Fill out the template with your design. 6 | -------------------------------------------------------------------------------- /docs/overview.md: -------------------------------------------------------------------------------- 1 | # Hiero Block Node Documentation Overview 2 | 3 | This document will outline the structure and content of Block Node documentation. 4 | 5 | ## Table of Contents 6 | 7 | 1. [Projects](#projects) 8 | 2. [Concepts](#concepts) 9 | 3. [Release](#release) 10 | 11 | ## Projects 12 | 13 | - [Hiero Block Node](block-node/README.md): Provides an introduction to Hiero Block Node, its purpose and how it can be used. 14 | - [Simulator](simulator/README.md): Offers instructions on how the Simulator can be utilized. 15 | - [Tools](tools/README.md): Provides information on the command line tools available. 16 | 17 | ## Concepts 18 | 19 | - [Hiero Block Node Protocol](design/communication-protocol/README.md): Overview of the Hiero Block Node Protocol 20 | 21 | ## Release 22 | 23 | - [Release Process Documentation](release.md): Details the steps involved in creating a new release, tagging, and publishing artifacts. 24 | -------------------------------------------------------------------------------- /docs/tools/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart of the Tools 2 | 3 | ## Table of Contents 4 | 5 | 1. [Running locally](#running-locally) 6 | 1. [Build the Tools](#build-the-tools) 7 | 2. [Run the Tools](#run-the-tools) 8 | 9 | ## Running locally 10 | 11 | - Tools subproject qualifier: `:tools` 12 | - Assuming your working directory is the repo root 13 | 14 | > **NOTE:** one may use the `-p` flag for `./gradlew` in order to avoid 15 | > specifying the target subproject repeatedly on each task when running 16 | > multiple tasks. When running only a single task, however, it is 17 | > recommended to use the project qualifier (i.e. `:tools:`) for 18 | > both simplicity and clarity. 19 | 20 | ### Easy way for Unix based OSs 21 | 22 | There is a command line script for building and running tool, which is located in the root of the repository. It has the 23 | nice extra feature of giving you colored console output. 24 | 25 | ```bash 26 | ./tool.sh info --help 27 | ``` 28 | 29 | ### Build the Tools 30 | 31 | > **NOTE:** if you have not done so already, it is 32 | > generally recommended to build the entire repo first: 33 | > 34 | > ```bash 35 | > ./gradlew clean build -x test 36 | > ``` 37 | 38 | 1. To quickly build the Tools sources (without running tests), do the following: 39 | 40 | ```bash 41 | ./gradlew -p tools clean build -x test 42 | ``` 43 | 44 | ### Run the Tools 45 | 46 | 1. To run the Tools, do the following: 47 | 48 | ```bash 49 | # Here is an example of running the info command with the help option, simply 50 | # replace `info --help` with the desired command and options to run the tools 51 | # quickly using the `./gradlew run` task. 52 | ./gradlew -q :tools:run --args="info --help" 53 | ``` 54 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Need increased heap for running Gradle itself, or SonarQube will run the JVM out of metaspace 2 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 3 | 4 | # Enable Gradle Caching 5 | org.gradle.configuration-cache=true 6 | org.gradle.caching=true 7 | org.gradle.parallel=true 8 | 9 | # Disable publish signing by default 10 | publishSigningEnabled=false 11 | -------------------------------------------------------------------------------- /gradle/aggregation/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { 3 | id("org.hiero.gradle.feature.publish-maven-central-aggregation") 4 | id("org.hiero.gradle.report.code-coverage") 5 | id("org.hiero.gradle.check.spotless") 6 | id("org.hiero.gradle.check.spotless-kotlin") 7 | } 8 | 9 | dependencies { 10 | published(project(":block-node-protobuf-sources")) 11 | 12 | implementation(project(":block-node-app")) 13 | implementation(project(":simulator")) 14 | implementation(project(":suites")) 15 | implementation(project(":tools")) 16 | } 17 | -------------------------------------------------------------------------------- /gradle/modules.properties: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Jars that are not yet modules used in the 'tools' project 4 | com.google.api.gax=com.google.api:gax 5 | com.google.auth.oauth2=com.google.auth:google-auth-library-oauth2-http 6 | com.google.cloud.core=com.google.cloud:google-cloud-core 7 | com.google.cloud.storage=com.google.cloud:google-cloud-storage 8 | -------------------------------------------------------------------------------- /gradle/toolchain-versions.properties: -------------------------------------------------------------------------------- 1 | jdk=21.0.6 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 6 | networkTimeout=10000 7 | validateDistributionUrl=true 8 | zipStoreBase=GRADLE_USER_HOME 9 | zipStorePath=wrapper/dists 10 | -------------------------------------------------------------------------------- /protobuf-sources/.gitignore: -------------------------------------------------------------------------------- 1 | *.tgz 2 | -------------------------------------------------------------------------------- /protobuf-sources/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { id("org.hiero.gradle.module.library") } 3 | 4 | description = "Hiero Block Node Protobuf Sources" 5 | 6 | // Add probuf source files as resources to have them packaged in Jar 7 | sourceSets.main { resources { srcDir(layout.projectDirectory.dir("src/main/proto")) } } 8 | 9 | // Skip javadoc generation for this module as it only contains protobuf sources 10 | tasks.javadoc { enabled = false } 11 | 12 | val generateBlockNodeProtoArtifact: TaskProvider = 13 | tasks.register("generateBlockNodeProtoArtifact") { 14 | description = 15 | "Retrieves CN protobuf and combines it along with local BN protobuf into a single artifact" 16 | group = "protobuf" 17 | 18 | workingDir(layout.projectDirectory) 19 | val cnTagHash = "efb0134e921b32ed6302da9c93874d65492e876f" // v0.62.2 20 | 21 | // run build-bn-proto.sh skipping inclusion of BN API as it messes up proto considerations 22 | commandLine( 23 | "sh", 24 | "-c", 25 | "${layout.projectDirectory}/scripts/build-bn-proto.sh -t $cnTagHash -v ${project.version} -o ${layout.projectDirectory}/block-node-protobuf -i true -b ${layout.projectDirectory}/src/main/proto/", 26 | ) 27 | } 28 | 29 | val cleanUpAfterBlockNodeProtoArtifact: TaskProvider = 30 | tasks.register("cleanUpAfterBlockNodeProtoArtifact") { 31 | description = "Cleans up left over files from generateBlockNodeProtoArtifact task" 32 | group = "protobuf" 33 | 34 | workingDir(layout.projectDirectory) 35 | 36 | // clean up intermediate files generated from build-bn-proto.sh run 37 | commandLine( 38 | "rm", 39 | "-rf", 40 | "${layout.projectDirectory}/block-node-protobuf", 41 | "&&", 42 | "rm", 43 | "-rf", 44 | "${layout.projectDirectory}/hiero-consensus-node", 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /protobuf-sources/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | module org.hiero.block.protobuf.sources {} 3 | -------------------------------------------------------------------------------- /protobuf-sources/src/main/proto/block-node/api/reconnect_service.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | syntax = "proto3"; 3 | 4 | package org.hiero.block.api; 5 | 6 | option java_package = "org.hiero.block.api.protoc"; 7 | // <<>> This comment is special code for setting PBJ Compiler java package 8 | option java_multiple_files = true; 9 | 10 | message ReconnectRequest {} 11 | 12 | message ReconnectResponse {} 13 | 14 | /** 15 | * Remote procedure calls (RPCs) for the Block Node reconnect services. 16 | */ 17 | service ReconnectService { 18 | /** 19 | * Request reconnect data comprised of state and block data from the block node. 20 | */ 21 | rpc reconnect(ReconnectRequest) returns (stream ReconnectResponse); 22 | } 23 | -------------------------------------------------------------------------------- /protobuf-sources/src/main/proto/block-node/api/shared_message_types.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | syntax = "proto3"; 3 | 4 | package org.hiero.block.api; 5 | 6 | option java_package = "org.hiero.block.api.protoc"; 7 | // <<>> This comment is special code for setting PBJ Compiler java package 8 | option java_multiple_files = true; 9 | 10 | import "block/stream/block_item.proto"; 11 | 12 | /** 13 | * A wrapper around a repeated BlockItem.
14 | * This message is required so that we can include ordered lists of block 15 | * items as `oneof` alternatives in streams. 16 | * 17 | * Each `BlockItemSet` MUST contain at least one `BlockItem`, 18 | * and MAY contain up to one full block.
19 | * A single `BlockItemSet` SHALL NOT contain block items from 20 | * more than one block.
21 | * If a `BlockHeader` is present in a `BlockItemSet`, that item 22 | * MUST be the first item in the list.
23 | * If a `BlockProof` is present in a `BlockItemSet`, that item 24 | * MUST be the last item in the list. 25 | */ 26 | message BlockItemSet { 27 | /** 28 | * An ordered list of `BlockItem`s.
29 | * This list supports sending block items to subscribers in batches 30 | * for greater channel efficiency. 31 | */ 32 | repeated com.hedera.hapi.block.stream.BlockItem block_items = 1; 33 | } 34 | -------------------------------------------------------------------------------- /protobuf-sources/src/main/proto/internal/unparsed.proto: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | syntax = "proto3"; 3 | 4 | package org.hiero.block.internal; 5 | 6 | option java_package = "org.hiero.block.internal.protoc"; 7 | // <<>> This comment is special code for setting PBJ Compiler java package 8 | option java_multiple_files = true; 9 | 10 | import "block-node/api/block_access_service.proto"; 11 | import "block-node/api/block_stream_subscribe_service.proto"; 12 | 13 | message PublishStreamRequestUnparsed { 14 | BlockItemSetUnparsed block_items = 1; 15 | } 16 | 17 | message SubscribeStreamResponseUnparsed { 18 | oneof response { 19 | /** 20 | * A final response item describing the terminal status of this stream. 21 | *

22 | * The block node server SHALL end the stream following this message. 23 | */ 24 | org.hiero.block.api.SubscribeStreamResponse.Code status = 1; 25 | 26 | /** 27 | * A stream response item containing one or more `BlockItem`s. 28 | *

29 | * The full stream SHALL consist of many `block_items` messages 30 | * followed by a single `status` message. 31 | */ 32 | BlockItemSetUnparsed block_items = 2; 33 | } 34 | } 35 | 36 | message BlockResponseUnparsed { 37 | org.hiero.block.api.BlockResponse.Code status = 1; 38 | BlockUnparsed block = 2; 39 | } 40 | 41 | message BlockUnparsed { 42 | repeated BlockItemUnparsed block_items = 1; 43 | } 44 | 45 | message BlockItemSetUnparsed { 46 | repeated BlockItemUnparsed block_items = 1; 47 | } 48 | 49 | message BlockItemUnparsed { 50 | oneof item { 51 | bytes block_header = 1; 52 | bytes event_header = 2; 53 | bytes round_header = 3; 54 | bytes event_transaction = 4; 55 | bytes transaction_result = 5; 56 | bytes transaction_output = 6; 57 | bytes state_changes = 7; 58 | bytes filtered_item_hash = 8; 59 | bytes block_proof = 9; 60 | bytes record_file = 10; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tool.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # run gradle jar build and send output to /dev/null 4 | ./gradlew -q tool:shadowJar > /dev/null 5 | # check if last command failed and exit if so 6 | if [ $? -ne 0 ]; then 7 | echo "Build failed" 8 | exit 1 9 | fi 10 | # change to the tools directory 11 | pushd tools > /dev/null 12 | # find the jar name in the build/libs directory 13 | JAR=$(find build/libs -name 'tools-*-all.jar') 14 | # run the command line tool built jar file forwarding all arguments 15 | java -jar $JAR "$@" 16 | # change back to the original directory 17 | popd > /dev/null 18 | -------------------------------------------------------------------------------- /tools-and-tests/protobuf-protoc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { 3 | id("org.hiero.gradle.module.library") 4 | id("org.hiero.gradle.feature.protobuf") 5 | } 6 | 7 | description = "Hiero Block Node Protobuf Protoc API" 8 | 9 | sourceSets { 10 | main { 11 | proto { 12 | // use sources from 'protobuf' module 13 | srcDir(layout.projectDirectory.dir("../../protobuf-sources/src/main/proto")) 14 | // use sources from CN repository cloned by 'protobuf' module (see task dependency) 15 | srcDir(layout.projectDirectory.dir("../../protobuf-sources/block-node-protobuf")) 16 | // exclude BN files at root level 17 | exclude("*.proto") 18 | } 19 | } 20 | } 21 | 22 | // jjohannes: remove cross-project task dependency once the following issue is addressed 23 | // https://github.com/hiero-ledger/hiero-gradle-conventions/issues/185 24 | tasks.generateProto { dependsOn(":block-node-protobuf-sources:generateBlockNodeProtoArtifact") } 25 | -------------------------------------------------------------------------------- /tools-and-tests/protobuf-protoc/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | open module org.hiero.block.protobuf.protoc { 3 | exports com.hedera.hapi.services.auxiliary.hints.legacy; 4 | exports com.hedera.hapi.services.auxiliary.tss.legacy; 5 | exports com.hedera.hapi.services.auxiliary.history.legacy; 6 | exports com.hedera.hapi.node.state.tss.legacy; 7 | exports com.hedera.services.stream.proto; 8 | exports com.hederahashgraph.api.proto.java; 9 | exports com.hedera.hapi.block.stream.protoc; 10 | exports com.hedera.hapi.block.stream.input.protoc; 11 | exports com.hedera.hapi.block.stream.output.protoc; 12 | exports com.hedera.hapi.platform.event.legacy; 13 | exports com.hedera.hapi.platform.state.legacy; 14 | exports org.hiero.block.api.protoc; 15 | exports org.hiero.block.internal.protoc; 16 | 17 | requires transitive com.google.common; 18 | requires transitive com.google.protobuf; 19 | requires transitive io.grpc.stub; 20 | requires transitive io.grpc; 21 | requires io.grpc.protobuf; 22 | requires static com.github.spotbugs.annotations; 23 | requires static java.annotation; 24 | } 25 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:21 2 | 3 | # Create a non-root user and group 4 | ARG UNAME=hedera 5 | ARG UID=2000 6 | ARG GID=2000 7 | ARG BN_WORKDIR="/opt/hiero/block-node" 8 | ENV BN_WORKDIR=${BN_WORKDIR} 9 | RUN groupadd --gid $GID $UNAME 10 | RUN useradd --no-user-group --create-home --uid $UID --gid $GID --shell /bin/bash hedera 11 | WORKDIR ${BN_WORKDIR} 12 | 13 | # Copy the distribution and resources 14 | COPY simulator-*.tar ./simulator.tar 15 | 16 | RUN mkdir -p ${BN_WORKDIR}/logs/config 17 | COPY logging.properties ${BN_WORKDIR}/logs/config/logging.properties 18 | 19 | # Extract the distribution and block data 20 | RUN tar -xf simulator.tar && \ 21 | rm simulator.tar && \ 22 | cd ${BN_WORKDIR} && \ 23 | chown -R $UID:$GID ${BN_WORKDIR} 24 | 25 | # Switch to non-root user 26 | USER $UNAME 27 | 28 | # Run the simulator using the extracted directory name 29 | RUN SIMULATOR_DIR=$(ls -d simulator-*/) && \ 30 | echo "#!/bin/bash\n${BN_WORKDIR}/${SIMULATOR_DIR}bin/simulator" > ${BN_WORKDIR}/start.sh && \ 31 | chmod +x ${BN_WORKDIR}/start.sh 32 | 33 | ENTRYPOINT ["sh","-c","${BN_WORKDIR}/start.sh"] 34 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/docker/docker-compose-publisher-consumer.yml: -------------------------------------------------------------------------------- 1 | services: 2 | simulator-publisher: 3 | container_name: simulator-publisher 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | image: hedera-block-simulator:latest 8 | networks: 9 | - block-node_default 10 | env_file: 11 | - .env 12 | environment: 13 | - BLOCK_STREAM_SIMULATOR_MODE=${PUBLISHER_BLOCK_STREAM_SIMULATOR_MODE} 14 | - PROMETHEUS_ENDPOINT_PORT_NUMBER=${PUBLISHER_PROMETHEUS_ENDPOINT_PORT_NUMBER} 15 | healthcheck: 16 | test: ["CMD", "curl", "-f", "http://localhost:9998/metrics"] 17 | interval: 3s 18 | timeout: 10s 19 | retries: 5 20 | volumes: 21 | - simulator_data:/opt/simulator/data 22 | 23 | simulator-consumer: 24 | container_name: simulator-consumer 25 | build: 26 | context: . 27 | dockerfile: Dockerfile 28 | image: hedera-block-simulator:latest 29 | networks: 30 | - block-node_default 31 | env_file: 32 | - .env 33 | environment: 34 | - BLOCK_STREAM_SIMULATOR_MODE=${CONSUMER_BLOCK_STREAM_SIMULATOR_MODE} 35 | - PROMETHEUS_ENDPOINT_PORT_NUMBER=${CONSUMER_PROMETHEUS_ENDPOINT_PORT_NUMBER} 36 | depends_on: 37 | simulator-publisher: 38 | condition: service_healthy 39 | 40 | networks: 41 | block-node_default: 42 | name: block-node_default 43 | external: true 44 | 45 | volumes: 46 | simulator_data: 47 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/docker/docker-compose-publisher.yml: -------------------------------------------------------------------------------- 1 | services: 2 | simulator-publisher: 3 | container_name: simulator-publisher 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | image: hedera-block-simulator:latest 8 | networks: 9 | - block-node_default 10 | ports: 11 | - "5006:5006" 12 | env_file: 13 | - .env 14 | environment: 15 | - BLOCK_STREAM_SIMULATOR_MODE=${PUBLISHER_BLOCK_STREAM_SIMULATOR_MODE} 16 | - PROMETHEUS_ENDPOINT_PORT_NUMBER=${PUBLISHER_PROMETHEUS_ENDPOINT_PORT_NUMBER} 17 | healthcheck: 18 | test: ["CMD", "curl", "-f", "http://localhost:9998/metrics"] 19 | interval: 3s 20 | timeout: 10s 21 | retries: 5 22 | volumes: 23 | - simulator_data:/opt/simulator/data 24 | 25 | networks: 26 | block-node_default: 27 | name: block-node_default 28 | external: true 29 | 30 | volumes: 31 | simulator_data: 32 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/docker/update-env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script creates a '.env' file that is used for docker-compose as input for environment variables 4 | # for the simulator services. 5 | 6 | echo "Creating .env file for simulator services..." 7 | 8 | # Generate .env file with default values 9 | cat > .env << EOL 10 | GRPC_SERVER_ADDRESS=block-node-server 11 | PROMETHEUS_ENDPOINT_ENABLED=true 12 | 13 | # For publisher service 14 | PUBLISHER_BLOCK_STREAM_SIMULATOR_MODE=PUBLISHER_CLIENT 15 | PUBLISHER_PROMETHEUS_ENDPOINT_PORT_NUMBER=9998 16 | 17 | # For consumer service 18 | CONSUMER_BLOCK_STREAM_SIMULATOR_MODE=CONSUMER 19 | CONSUMER_PROMETHEUS_ENDPOINT_PORT_NUMBER=9997 20 | EOL 21 | 22 | logging_config_file_arg="-Djava.util.logging.config.file=/opt/hiero/block-node/logs/config/logging.properties" 23 | debug_arg="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5006" 24 | # determine if we should include debug opts 25 | [ "$1" = true ] && is_debug=true || is_debug=false 26 | if [ true = "$is_debug" ]; then 27 | # The server will wait for the debugger to attach on port 5006 28 | echo "JAVA_TOOL_OPTIONS=${logging_config_file_arg} ${debug_arg}" >> .env 29 | else 30 | echo "JAVA_TOOL_OPTIONS=${logging_config_file_arg}" >> .env 31 | fi 32 | 33 | # Output the values 34 | echo ".env properties:" 35 | cat .env 36 | echo 37 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | import org.hiero.block.simulator.config.SimulatorConfigExtension; 3 | 4 | module org.hiero.block.simulator { 5 | exports org.hiero.block.simulator.config.data; 6 | exports org.hiero.block.simulator.exception; 7 | exports org.hiero.block.simulator; 8 | exports org.hiero.block.simulator.config.types; 9 | exports org.hiero.block.simulator.config; 10 | exports org.hiero.block.simulator.grpc; 11 | exports org.hiero.block.simulator.generator; 12 | exports org.hiero.block.simulator.metrics; 13 | exports org.hiero.block.simulator.grpc.impl; 14 | exports org.hiero.block.simulator.mode; 15 | exports org.hiero.block.simulator.mode.impl; 16 | exports org.hiero.block.simulator.config.logging to 17 | com.swirlds.config.impl; 18 | 19 | requires com.hedera.pbj.runtime; 20 | requires com.swirlds.common; 21 | requires com.swirlds.config.api; 22 | requires com.swirlds.config.extensions; 23 | requires com.swirlds.metrics.api; 24 | requires org.hiero.block.common; 25 | requires org.hiero.block.protobuf.pbj; 26 | requires org.hiero.block.protobuf.protoc; 27 | requires com.google.protobuf; 28 | requires dagger; 29 | requires io.grpc.stub; 30 | requires io.grpc; 31 | requires java.logging; 32 | requires javax.inject; 33 | requires static transitive com.github.spotbugs.annotations; 34 | requires static transitive com.google.auto.service; 35 | requires static java.compiler; // javax.annotation.processing.Generated 36 | 37 | provides com.swirlds.config.api.ConfigurationExtension with 38 | SimulatorConfigExtension; 39 | } 40 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/BlockStreamSimulatorInjectionComponent.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator; 3 | 4 | import com.swirlds.config.api.Configuration; 5 | import dagger.BindsInstance; 6 | import dagger.Component; 7 | import javax.inject.Singleton; 8 | import org.hiero.block.simulator.config.ConfigInjectionModule; 9 | import org.hiero.block.simulator.generator.GeneratorInjectionModule; 10 | import org.hiero.block.simulator.grpc.GrpcInjectionModule; 11 | import org.hiero.block.simulator.metrics.MetricsInjectionModule; 12 | import org.hiero.block.simulator.mode.SimulatorModeInjectionModule; 13 | import org.hiero.block.simulator.startup.StartupDataInjectionModule; 14 | 15 | /** The component used to inject the block stream simulator into the application. */ 16 | @Singleton 17 | @Component( 18 | modules = { 19 | MetricsInjectionModule.class, 20 | ConfigInjectionModule.class, 21 | GeneratorInjectionModule.class, 22 | GrpcInjectionModule.class, 23 | SimulatorModeInjectionModule.class, 24 | StartupDataInjectionModule.class 25 | }) 26 | public interface BlockStreamSimulatorInjectionComponent { 27 | 28 | /** 29 | * Gets the block stream simulator. 30 | * 31 | * @return the block stream simulator 32 | */ 33 | BlockStreamSimulatorApp getBlockStreamSimulatorApp(); 34 | 35 | /** The factory used to create the block stream simulator injection component. */ 36 | @Component.Factory 37 | interface Factory { 38 | /** 39 | * Creates the block stream simulator injection component. 40 | * 41 | * @param configuration the configuration to be used by the block stream simulator 42 | * @return the block stream simulator injection component 43 | */ 44 | BlockStreamSimulatorInjectionComponent create(@BindsInstance Configuration configuration); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/Constants.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator; 3 | 4 | /** The Constants class defines the constants for the block simulator. */ 5 | public final class Constants { 6 | /** The file extension for block files. */ 7 | public static final String RECORD_EXTENSION = ".blk"; 8 | 9 | /** postfix for gzip files */ 10 | public static final String GZ_EXTENSION = ".gz"; 11 | 12 | /** 13 | * Used for converting nanoseconds to milliseconds and vice versa 14 | */ 15 | public static final int NANOS_PER_MILLI = 1_000_000; 16 | 17 | /** Constructor to prevent instantiation. this is only a utility class */ 18 | private Constants() {} 19 | } 20 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/SimulatorConfigExtension.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config; 3 | 4 | import com.google.auto.service.AutoService; 5 | import com.swirlds.common.metrics.config.MetricsConfig; 6 | import com.swirlds.common.metrics.platform.prometheus.PrometheusConfig; 7 | import com.swirlds.config.api.ConfigurationExtension; 8 | import edu.umd.cs.findbugs.annotations.NonNull; 9 | import java.util.Set; 10 | import org.hiero.block.simulator.config.data.BlockGeneratorConfig; 11 | import org.hiero.block.simulator.config.data.BlockStreamConfig; 12 | import org.hiero.block.simulator.config.data.ConsumerConfig; 13 | import org.hiero.block.simulator.config.data.GrpcConfig; 14 | import org.hiero.block.simulator.config.data.SimulatorStartupDataConfig; 15 | import org.hiero.block.simulator.config.data.UnorderedStreamConfig; 16 | 17 | /** Sets up configuration for services. */ 18 | @AutoService(ConfigurationExtension.class) 19 | public class SimulatorConfigExtension implements ConfigurationExtension { 20 | 21 | /** Explicitly defined constructor. */ 22 | public SimulatorConfigExtension() { 23 | super(); 24 | } 25 | 26 | @NonNull 27 | @Override 28 | public Set> getConfigDataTypes() { 29 | return Set.of( 30 | BlockStreamConfig.class, 31 | UnorderedStreamConfig.class, 32 | ConsumerConfig.class, 33 | GrpcConfig.class, 34 | BlockGeneratorConfig.class, 35 | SimulatorStartupDataConfig.class, 36 | MetricsConfig.class, 37 | PrometheusConfig.class); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/data/ConsumerConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.data; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import org.hiero.block.simulator.config.logging.Loggable; 7 | import org.hiero.block.simulator.config.types.SlowDownType; 8 | 9 | /** 10 | * Defines the configuration data for the consumer. 11 | * 12 | * @param startBlockNumber the block number from which to start consuming 13 | * @param endBlockNumber the block number at which to stop consuming 14 | * @param slowDownType the type of slowdown to apply while consuming 15 | * @param slowDownMilliseconds the slowdown in milliseconds 16 | * @param slowDownForBlockRange the range of blocks to apply the slowdown 17 | */ 18 | @ConfigData("consumer") 19 | public record ConsumerConfig( 20 | @Loggable @ConfigProperty(defaultValue = "-1") long startBlockNumber, 21 | @Loggable @ConfigProperty(defaultValue = "-1") long endBlockNumber, 22 | @Loggable @ConfigProperty(defaultValue = "NONE") SlowDownType slowDownType, 23 | @Loggable @ConfigProperty(defaultValue = "2") long slowDownMilliseconds, 24 | @Loggable @ConfigProperty(defaultValue = "10-30") String slowDownForBlockRange) {} 25 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/data/GrpcConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.data; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import com.swirlds.config.api.validation.annotation.Max; 7 | import com.swirlds.config.api.validation.annotation.Min; 8 | import org.hiero.block.simulator.config.logging.Loggable; 9 | 10 | /** 11 | * The GrpcConfig class defines the configuration data for the gRPC client. 12 | * 13 | * @param serverAddress the address of the gRPC server 14 | * @param port the port of the gRPC server 15 | */ 16 | @ConfigData("grpc") 17 | public record GrpcConfig( 18 | @Loggable @ConfigProperty(defaultValue = "localhost") String serverAddress, 19 | @Loggable @ConfigProperty(defaultValue = "8080") @Min(0) @Max(65535) int port) {} 20 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/data/SimulatorStartupDataConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.data; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | import java.nio.file.Path; 7 | import java.util.Objects; 8 | import org.hiero.block.simulator.config.logging.Loggable; 9 | 10 | /** 11 | * Config record for the startup data functionality. 12 | * 13 | * @param enabled whether the startup data functionality is enabled 14 | * @param latestAckBlockNumberPath path to the file containing the latest 15 | * acknowledged block number 16 | * @param latestAckBlockHashPath path to the file containing the latest 17 | */ 18 | @ConfigData("simulator.startup.data") 19 | public record SimulatorStartupDataConfig( 20 | @Loggable @ConfigProperty(defaultValue = "false") boolean enabled, 21 | @Loggable @ConfigProperty(defaultValue = "/opt/simulator/data/latestAckBlockNumber") 22 | Path latestAckBlockNumberPath, 23 | @Loggable @ConfigProperty(defaultValue = "/opt/simulator/data/latestAckBlockHash") 24 | Path latestAckBlockHashPath) { 25 | public SimulatorStartupDataConfig { 26 | Objects.requireNonNull(latestAckBlockNumberPath); 27 | Objects.requireNonNull(latestAckBlockHashPath); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/logging/ConfigurationLogging.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.logging; 3 | 4 | /** 5 | * Use this interface to log configuration data. 6 | */ 7 | public interface ConfigurationLogging { 8 | /** 9 | * Log the configuration data. 10 | */ 11 | void log(); 12 | } 13 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/logging/Loggable.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.logging; 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * This annotation is used to mark record components that should be logged. 11 | */ 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target({ElementType.RECORD_COMPONENT}) 14 | public @interface Loggable {} 15 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/types/GenerationMode.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.types; 3 | 4 | /** The GenerationMode enum defines the modes of generation for the block stream. */ 5 | public enum GenerationMode { 6 | /** Reads Blocks from a Folder. */ 7 | DIR, 8 | /** Generates Blocks from rules */ 9 | CRAFT 10 | } 11 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/types/MidBlockFailType.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.types; 3 | 4 | /** The MidBlockFailType enum defines the type of failure in the process of block streaming. 5 | * Failure will occur randomly between the header and the proof of the block. */ 6 | public enum MidBlockFailType { 7 | /** 8 | * The NONE value indicates no failure will be simulated during streaming. 9 | */ 10 | NONE, 11 | /** 12 | * The ABRUPT value indicates that an abrupt disconnection will occur while streaming 13 | * (without closing the connection or sending an EndOfStream message). 14 | */ 15 | ABRUPT, 16 | /** 17 | * The EOS value indicates that an EndOfStream message will be sent before the final item of the block. 18 | * Currently, onError is called, as the client is not able to send actual EOS message 19 | */ 20 | EOS 21 | } 22 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/types/SimulatorMode.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.types; 3 | 4 | /** The SimulatorMode enum defines the work modes of the block stream simulator. */ 5 | public enum SimulatorMode { 6 | /** 7 | * Indicates a work mode in which the simulator is working in consumer mode. 8 | */ 9 | CONSUMER, 10 | /** 11 | * Indicates a work mode in which the simulator is working as both consumer and publisher. 12 | */ 13 | PUBLISHER_SERVER, 14 | /** 15 | * Indicates a work mode in which the simulator is working in publisher mode. 16 | */ 17 | PUBLISHER_CLIENT 18 | } 19 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/config/types/StreamingMode.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.types; 3 | 4 | /** The StreamingMode enum defines the different modes for streaming blocks. */ 5 | public enum StreamingMode { 6 | 7 | /** It will wait X Nanos between each block. */ 8 | CONSTANT_RATE, 9 | 10 | /** It will attempt to send a block each X Millis. */ 11 | MILLIS_PER_BLOCK; 12 | 13 | /** 14 | * Converts a string to a StreamingMode. 15 | * 16 | * @param mode the string to convert 17 | * @return the StreamingMode 18 | */ 19 | public static StreamingMode fromString(String mode) { 20 | return switch (mode) { 21 | case "CONSTANT_RATE" -> CONSTANT_RATE; 22 | case "MILLIS_PER_BLOCK" -> MILLIS_PER_BLOCK; 23 | default -> throw new IllegalArgumentException("Invalid mode: " + mode); 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/exception/BlockSimulatorParsingException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.exception; 3 | 4 | /** Use this checked exception to represent a Block Simulator parsing exception. */ 5 | public class BlockSimulatorParsingException extends Exception { 6 | /** 7 | * Constructs a new parsing exception with the specified detail message. 8 | * 9 | * @param message the detail message 10 | */ 11 | public BlockSimulatorParsingException(final String message) { 12 | super(message); 13 | } 14 | 15 | /** 16 | * Constructs a new parsing exception with the specified cause. 17 | * 18 | * @param cause the cause of the exception, could be null, see super javadoc 19 | */ 20 | public BlockSimulatorParsingException(final Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/generator/BlockStreamManager.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.generator; 3 | 4 | import com.hedera.hapi.block.stream.protoc.Block; 5 | import com.hedera.hapi.block.stream.protoc.BlockItem; 6 | import java.io.IOException; 7 | import org.hiero.block.simulator.config.types.GenerationMode; 8 | import org.hiero.block.simulator.exception.BlockSimulatorParsingException; 9 | 10 | /** The block stream manager interface. */ 11 | public interface BlockStreamManager { 12 | 13 | /** 14 | * Initialize the block stream manager and load blocks into memory. 15 | */ 16 | default void init() {} 17 | 18 | /** 19 | * Get the generation mode. 20 | * 21 | * @return the generation mode 22 | */ 23 | GenerationMode getGenerationMode(); 24 | 25 | /** 26 | * Get the next block item. 27 | * 28 | * @return the next block item 29 | * @throws IOException if a I/O error occurs 30 | * @throws BlockSimulatorParsingException if a parse error occurs 31 | */ 32 | BlockItem getNextBlockItem() throws IOException, BlockSimulatorParsingException; 33 | 34 | /** 35 | * Get the next block. 36 | * 37 | * @return the next block 38 | * @throws IOException if a I/O error occurs 39 | * @throws BlockSimulatorParsingException if a parse error occurs 40 | */ 41 | Block getNextBlock() throws IOException, BlockSimulatorParsingException; 42 | } 43 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/generator/itemhandler/BlockHeaderHandler.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.generator.itemhandler; 3 | 4 | import static java.util.Objects.requireNonNull; 5 | 6 | import com.hedera.hapi.block.stream.output.protoc.BlockHeader; 7 | import com.hedera.hapi.block.stream.protoc.BlockItem; 8 | import com.hederahashgraph.api.proto.java.BlockHashAlgorithm; 9 | import edu.umd.cs.findbugs.annotations.NonNull; 10 | 11 | /** 12 | * Handler for block headers in the block stream. 13 | * Creates and manages block header items containing metadata about the block. 14 | */ 15 | public class BlockHeaderHandler extends AbstractBlockItemHandler { 16 | private final byte[] previousBlockHash; 17 | private final long currentBlockNumber; 18 | 19 | /** 20 | * Constructs a new BlockHeaderHandler. 21 | * 22 | * @param previousBlockHash Hash of the previous block in the chain 23 | * @param currentBlockNumber Number of the current block 24 | * @throws NullPointerException if previousBlockHash is null 25 | */ 26 | public BlockHeaderHandler(@NonNull final byte[] previousBlockHash, final long currentBlockNumber) { 27 | this.previousBlockHash = requireNonNull(previousBlockHash); 28 | this.currentBlockNumber = currentBlockNumber; 29 | } 30 | 31 | @Override 32 | public BlockItem getItem() { 33 | if (blockItem == null) { 34 | blockItem = 35 | BlockItem.newBuilder().setBlockHeader(createBlockHeader()).build(); 36 | } 37 | return blockItem; 38 | } 39 | 40 | private BlockHeader createBlockHeader() { 41 | return BlockHeader.newBuilder() 42 | .setHapiProtoVersion(getSemanticVersion()) 43 | .setSoftwareVersion(getSemanticVersion()) 44 | .setHashAlgorithm(BlockHashAlgorithm.SHA2_384) 45 | .setBlockTimestamp(getTimestamp()) 46 | .setNumber(currentBlockNumber) 47 | .build(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/generator/itemhandler/EventHeaderHandler.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.generator.itemhandler; 3 | 4 | import com.hedera.hapi.block.stream.input.protoc.EventHeader; 5 | import com.hedera.hapi.block.stream.protoc.BlockItem; 6 | import com.hedera.hapi.platform.event.legacy.EventCore; 7 | 8 | /** 9 | * Handler for event headers in the block stream. 10 | * Creates and manages event header items containing metadata about events. 11 | */ 12 | public class EventHeaderHandler extends AbstractBlockItemHandler { 13 | @Override 14 | public BlockItem getItem() { 15 | if (blockItem == null) { 16 | blockItem = 17 | BlockItem.newBuilder().setEventHeader(createEventHeader()).build(); 18 | } 19 | return blockItem; 20 | } 21 | 22 | private EventHeader createEventHeader() { 23 | return EventHeader.newBuilder().setEventCore(createEventCore()).build(); 24 | } 25 | 26 | private EventCore createEventCore() { 27 | return EventCore.newBuilder() 28 | .setCreatorNodeId(generateRandomValue(1, 32)) 29 | .setVersion(getSemanticVersion()) 30 | .build(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/generator/itemhandler/EventTransactionHandler.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.generator.itemhandler; 3 | 4 | import com.hedera.hapi.block.stream.protoc.BlockItem; 5 | import com.hedera.hapi.platform.event.legacy.EventTransaction; 6 | 7 | /** 8 | * Handler for event transactions in the block stream. 9 | * Creates and manages event transaction items representing blockchain transactions. 10 | */ 11 | public class EventTransactionHandler extends AbstractBlockItemHandler { 12 | @Override 13 | public BlockItem getItem() { 14 | if (blockItem == null) { 15 | blockItem = BlockItem.newBuilder() 16 | .setEventTransaction(createEventTransaction()) 17 | .build(); 18 | } 19 | return blockItem; 20 | } 21 | 22 | private EventTransaction createEventTransaction() { 23 | // For now, we stick with empty EventTransaction, because otherwise we need to provide encoded transaction, 24 | // which we don't have. 25 | // This transaction data should correspond with the results in the transaction result item and others. 26 | return EventTransaction.newBuilder().build(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/generator/itemhandler/ItemHandler.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.generator.itemhandler; 3 | 4 | import com.hedera.hapi.block.stream.protoc.BlockItem; 5 | import org.hiero.block.internal.BlockItemUnparsed; 6 | import org.hiero.block.simulator.exception.BlockSimulatorParsingException; 7 | 8 | /** 9 | * Interface defining the contract for handling different types of block items. 10 | * Implementations handle specific types of items like block headers, proofs, events, and transactions. 11 | */ 12 | public interface ItemHandler { 13 | /** 14 | * Returns the block item in its protobuf format. 15 | * 16 | * @return The constructed BlockItem 17 | */ 18 | BlockItem getItem(); 19 | 20 | /** 21 | * Converts the block item to its unparsed format. 22 | * 23 | * @return The block item in unparsed format 24 | * @throws BlockSimulatorParsingException if there is an error parsing the block item 25 | */ 26 | BlockItemUnparsed unparseBlockItem() throws BlockSimulatorParsingException; 27 | } 28 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/grpc/GrpcInjectionModule.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.grpc; 3 | 4 | import dagger.Binds; 5 | import dagger.Module; 6 | import dagger.Provides; 7 | import java.util.concurrent.atomic.AtomicBoolean; 8 | import javax.inject.Singleton; 9 | import org.hiero.block.simulator.grpc.impl.ConsumerStreamGrpcClientImpl; 10 | import org.hiero.block.simulator.grpc.impl.PublishStreamGrpcClientImpl; 11 | import org.hiero.block.simulator.grpc.impl.PublishStreamGrpcServerImpl; 12 | 13 | /** The module used to inject the gRPC client. */ 14 | @Module 15 | public interface GrpcInjectionModule { 16 | 17 | /** 18 | * Binds the PublishStreamGrpcClient to the PublishStreamGrpcClientImpl. 19 | * 20 | * @param publishStreamGrpcClient the PublishStreamGrpcClientImpl 21 | * @return the PublishStreamGrpcClient 22 | */ 23 | @Singleton 24 | @Binds 25 | PublishStreamGrpcClient bindPublishStreamGrpcClient(PublishStreamGrpcClientImpl publishStreamGrpcClient); 26 | 27 | /** 28 | * Binds the ConsumerStreamGrpcClient to the ConsumerStreamGrpcClientImpl. 29 | * 30 | * @param consumerStreamGrpcClient the ConsumerStreamGrpcClientImpl 31 | * @return the ConsumerStreamGrpcClient 32 | */ 33 | @Singleton 34 | @Binds 35 | ConsumerStreamGrpcClient bindConsumerStreamGrpcClient(ConsumerStreamGrpcClientImpl consumerStreamGrpcClient); 36 | 37 | /** 38 | * Binds the PublishStreamGrpcServer to the PublishStreamGrpcServerImpl. 39 | * 40 | * @param PublishStreamGrpcServer the PublishStreamGrpcServerImpl 41 | * @return the ConsumerStreamGrpcClient 42 | */ 43 | @Singleton 44 | @Binds 45 | PublishStreamGrpcServer bindPublishStreamGrpcServer(PublishStreamGrpcServerImpl PublishStreamGrpcServer); 46 | 47 | /** 48 | * Provides the stream enabled flag 49 | * 50 | * @return the stream enabled flag 51 | */ 52 | @Singleton 53 | @Provides 54 | static AtomicBoolean provideStreamEnabledFlag() { 55 | return new AtomicBoolean(true); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/grpc/PublishStreamGrpcClient.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.grpc; 3 | 4 | import com.hedera.hapi.block.stream.protoc.Block; 5 | import java.util.List; 6 | 7 | /** 8 | * The PublishStreamGrpcClient interface provides the methods to stream the block and block item. 9 | */ 10 | public interface PublishStreamGrpcClient { 11 | /** 12 | * Initialize, opens a gRPC channel and creates the needed stubs with the passed configuration. 13 | */ 14 | void init(); 15 | 16 | /** 17 | * Streams the block. 18 | * 19 | * @param block the block to be streamed 20 | * @return true if the block is streamed successfully, false otherwise 21 | */ 22 | boolean streamBlock(Block block); 23 | 24 | /** 25 | * Sends a onCompleted message to the server and waits for a short period of time to ensure the message is sent. 26 | * 27 | * @throws InterruptedException if the thread is interrupted 28 | */ 29 | void completeStreaming() throws InterruptedException; 30 | 31 | /** 32 | * Gets the number of published blocks. 33 | * 34 | * @return the number of published blocks 35 | */ 36 | long getPublishedBlocks(); 37 | 38 | /** 39 | * Gets the last known statuses. 40 | * 41 | * @return the last known statuses 42 | */ 43 | List getLastKnownStatuses(); 44 | 45 | /** 46 | * Shutdowns the channel. 47 | * 48 | * @throws InterruptedException if the thread is interrupted 49 | */ 50 | void shutdown() throws InterruptedException; 51 | } 52 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/grpc/PublishStreamGrpcServer.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.grpc; 3 | 4 | import java.util.List; 5 | 6 | public interface PublishStreamGrpcServer { 7 | /** 8 | * Initialize, opens a gRPC channel and creates the needed services with the passed configuration. 9 | */ 10 | void init(); 11 | 12 | /** 13 | * Starts the gRPC server. 14 | */ 15 | void start(); 16 | 17 | /** 18 | * Gets the number of processed blocks. 19 | * 20 | * @return the number of published blocks 21 | */ 22 | long getProcessedBlocks(); 23 | 24 | /** 25 | * Gets the last known statuses. 26 | * 27 | * @return the last known statuses 28 | */ 29 | List getLastKnownStatuses(); 30 | 31 | /** 32 | * Shutdowns the server. 33 | * 34 | * @throws InterruptedException if the thread is interrupted 35 | */ 36 | void shutdown() throws InterruptedException; 37 | } 38 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/metrics/MetricsInjectionModule.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.metrics; 3 | 4 | import com.swirlds.common.metrics.platform.DefaultMetricsProvider; 5 | import com.swirlds.config.api.Configuration; 6 | import com.swirlds.metrics.api.Metrics; 7 | import dagger.Binds; 8 | import dagger.Module; 9 | import dagger.Provides; 10 | import javax.inject.Singleton; 11 | 12 | /** The module used to inject the metrics service and metrics into the application. */ 13 | @Module 14 | public interface MetricsInjectionModule { 15 | 16 | /** 17 | * Provides the metrics service. 18 | * 19 | * @param metricsService the metrics service to be used 20 | * @return the metrics service 21 | */ 22 | @Singleton 23 | @Binds 24 | MetricsService bindMetricsService(MetricsServiceImpl metricsService); 25 | 26 | /** 27 | * Provides the metrics. 28 | * 29 | * @param configuration the configuration to be used by the metrics 30 | * @return the metrics 31 | */ 32 | @Singleton 33 | @Provides 34 | static Metrics provideMetrics(Configuration configuration) { 35 | final DefaultMetricsProvider metricsProvider = new DefaultMetricsProvider(configuration); 36 | final Metrics metrics = metricsProvider.createGlobalMetrics(); 37 | metricsProvider.start(); 38 | return metrics; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/metrics/MetricsService.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.metrics; 3 | 4 | import com.swirlds.metrics.api.Counter; 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | 7 | /** Use member variables of this class to update metric data for the Hedera Block Node. */ 8 | public interface MetricsService { 9 | /** 10 | * Use this method to get a specific counter for the given metric type. 11 | * 12 | * @param key to get a specific counter 13 | * @return the counter 14 | */ 15 | Counter get(@NonNull SimulatorMetricTypes.Counter key); 16 | } 17 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/metrics/MetricsServiceImpl.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.metrics; 3 | 4 | import com.swirlds.metrics.api.Counter; 5 | import com.swirlds.metrics.api.Metrics; 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import java.util.EnumMap; 8 | import javax.inject.Inject; 9 | 10 | /** 11 | * Use member variables of this class to update metric data for the Hedera Block Node. 12 | * 13 | *

Metrics are updated by calling the appropriate method on the metric object instance. For 14 | * example, to increment a counter, call {@link Counter#increment()}. 15 | */ 16 | public class MetricsServiceImpl implements MetricsService { 17 | 18 | private static final String CATEGORY = "hiero_block_node_simulator"; 19 | 20 | private final EnumMap counters = 21 | new EnumMap<>(SimulatorMetricTypes.Counter.class); 22 | 23 | /** 24 | * Create singleton instance of metrics service to be used throughout the application. 25 | * 26 | * @param metrics the metrics instance 27 | */ 28 | @Inject 29 | public MetricsServiceImpl(@NonNull final Metrics metrics) { 30 | // Initialize the counters 31 | for (SimulatorMetricTypes.Counter counter : SimulatorMetricTypes.Counter.values()) { 32 | counters.put( 33 | counter, 34 | metrics.getOrCreate(new Counter.Config(CATEGORY, counter.grafanaLabel()) 35 | .withDescription(counter.description()))); 36 | } 37 | } 38 | 39 | /** 40 | * Use this method to get a specific counter for the given metric type. 41 | * 42 | * @param key to get a specific counter 43 | * @return the counter 44 | */ 45 | @NonNull 46 | @Override 47 | public Counter get(@NonNull SimulatorMetricTypes.Counter key) { 48 | return counters.get(key); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/mode/SimulatorModeHandler.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.mode; 3 | 4 | import java.io.IOException; 5 | import org.hiero.block.simulator.exception.BlockSimulatorParsingException; 6 | 7 | /** 8 | * The {@code SimulatorModeHandler} interface defines the contract for implementing different 9 | * working modes of the Block Stream Simulator. Implementations of this interface handle 10 | * specific behaviors for starting the simulator and managing the streaming process, 11 | * depending on the selected mode. 12 | * 13 | *

Examples of working modes include: 14 | *

    15 | *
  • Consumer mode: The simulator consumes data from the block stream.
  • 16 | *
  • Publisher Client mode: The simulator publishes data to the block stream.
  • 17 | *
  • Publisher Server mode: The simulator receives blocks from client and sends back acknowledgments or errors.
  • 18 | *
19 | */ 20 | public interface SimulatorModeHandler { 21 | 22 | /** 23 | * Initializes the handler by setting up required resources and connections. 24 | * This method should be called before {@link #start()}. 25 | */ 26 | void init(); 27 | 28 | /** 29 | * Starts the simulator and initiates the streaming process according to the configured mode. 30 | * The behavior of this method depends on the specific working mode (consumer, publisher in client mode, or publisher in server mode). 31 | * 32 | * @throws BlockSimulatorParsingException if an error occurs while parsing blocks 33 | * @throws IOException if an I/O error occurs during block streaming 34 | * @throws InterruptedException if the thread running the simulator is interrupted 35 | */ 36 | void start() throws BlockSimulatorParsingException, IOException, InterruptedException; 37 | 38 | /** 39 | * Gracefully stops the handler, cleaning up resources and terminating any active streams. 40 | * 41 | * @throws InterruptedException if the shutdown process is interrupted 42 | */ 43 | void stop() throws InterruptedException; 44 | } 45 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/main/java/org/hiero/block/simulator/startup/StartupDataInjectionModule.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.startup; 3 | 4 | import dagger.Binds; 5 | import dagger.Module; 6 | import javax.inject.Singleton; 7 | import org.hiero.block.simulator.startup.impl.SimulatorStartupDataImpl; 8 | 9 | /** 10 | * Injection module for the startup data. 11 | */ 12 | @Module 13 | public interface StartupDataInjectionModule { 14 | /** 15 | * @param impl the implementation of the startup data 16 | * 17 | * @return valid, non-null, fully initialized singleton instance of the 18 | * startup data 19 | */ 20 | @Singleton 21 | @Binds 22 | SimulatorStartupData bindSimulatorStartupData(final SimulatorStartupDataImpl impl); 23 | } 24 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/java/org/hiero/block/simulator/config/logging/TestSecretConfig.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.logging; 3 | 4 | import com.swirlds.config.api.ConfigData; 5 | import com.swirlds.config.api.ConfigProperty; 6 | 7 | @ConfigData("test") 8 | public record TestSecretConfig( 9 | @ConfigProperty(defaultValue = "secretValue") String secret, 10 | @ConfigProperty(defaultValue = "") String emptySecret) {} 11 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/java/org/hiero/block/simulator/config/types/GenerationModeTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.types; 3 | 4 | import static org.junit.jupiter.api.Assertions.*; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | class GenerationModeTest { 9 | 10 | @Test 11 | void testGenerationMode() { 12 | GenerationMode mode = GenerationMode.DIR; 13 | assertEquals(GenerationMode.DIR, mode); 14 | mode = GenerationMode.CRAFT; 15 | assertEquals(GenerationMode.CRAFT, mode); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/java/org/hiero/block/simulator/config/types/StreamingModeTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.config.types; 3 | 4 | import static org.junit.jupiter.api.Assertions.*; 5 | 6 | class StreamingModeTest { 7 | 8 | @org.junit.jupiter.api.Test 9 | void fromString() { 10 | assertEquals(StreamingMode.CONSTANT_RATE, StreamingMode.fromString("CONSTANT_RATE")); 11 | assertEquals(StreamingMode.MILLIS_PER_BLOCK, StreamingMode.fromString("MILLIS_PER_BLOCK")); 12 | assertThrows(IllegalArgumentException.class, () -> StreamingMode.fromString("INVALID")); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/java/org/hiero/block/simulator/generator/itemhandler/EventHeaderHandlerTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.generator.itemhandler; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | import static org.junit.jupiter.api.Assertions.assertNotNull; 6 | import static org.junit.jupiter.api.Assertions.assertSame; 7 | import static org.junit.jupiter.api.Assertions.assertTrue; 8 | 9 | import com.hedera.hapi.block.stream.input.protoc.EventHeader; 10 | import com.hedera.hapi.block.stream.protoc.BlockItem; 11 | import com.hedera.hapi.platform.event.legacy.EventCore; 12 | import org.junit.jupiter.api.Test; 13 | 14 | class EventHeaderHandlerTest { 15 | 16 | @Test 17 | void testGetItem() { 18 | EventHeaderHandler handler = new EventHeaderHandler(); 19 | BlockItem item = handler.getItem(); 20 | 21 | assertNotNull(item); 22 | assertTrue(item.hasEventHeader()); 23 | 24 | EventHeader header = item.getEventHeader(); 25 | assertNotNull(header.getEventCore()); 26 | 27 | EventCore core = header.getEventCore(); 28 | assertTrue(core.getCreatorNodeId() >= 1 && core.getCreatorNodeId() < 32); 29 | assertNotNull(core.getVersion()); 30 | } 31 | 32 | @Test 33 | void testGetItemCaching() { 34 | EventHeaderHandler handler = new EventHeaderHandler(); 35 | BlockItem item1 = handler.getItem(); 36 | BlockItem item2 = handler.getItem(); 37 | 38 | assertSame(item1, item2, "getItem should return cached instance"); 39 | } 40 | 41 | @Test 42 | void testSemanticVersion() { 43 | EventHeaderHandler handler = new EventHeaderHandler(); 44 | EventCore core = handler.getItem().getEventHeader().getEventCore(); 45 | 46 | assertEquals(0, core.getVersion().getMajor()); 47 | assertEquals(1, core.getVersion().getMinor()); 48 | assertEquals(0, core.getVersion().getPatch()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/java/org/hiero/block/simulator/generator/itemhandler/EventTransactionHandlerTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.generator.itemhandler; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | import static org.junit.jupiter.api.Assertions.assertSame; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | import com.hedera.hapi.block.stream.protoc.BlockItem; 9 | import com.hedera.hapi.platform.event.legacy.EventTransaction; 10 | import org.junit.jupiter.api.Test; 11 | 12 | class EventTransactionHandlerTest { 13 | 14 | @Test 15 | void testGetItem() { 16 | EventTransactionHandler handler = new EventTransactionHandler(); 17 | BlockItem item = handler.getItem(); 18 | 19 | assertNotNull(item); 20 | assertTrue(item.hasEventTransaction()); 21 | 22 | EventTransaction transaction = item.getEventTransaction(); 23 | assertNotNull(transaction); 24 | } 25 | 26 | @Test 27 | void testGetItemCaching() { 28 | EventTransactionHandler handler = new EventTransactionHandler(); 29 | BlockItem item1 = handler.getItem(); 30 | BlockItem item2 = handler.getItem(); 31 | 32 | assertSame(item1, item2, "getItem should return cached instance"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/java/org/hiero/block/simulator/metrics/MetricsInjectionModuleTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.metrics; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | 6 | import com.swirlds.config.api.Configuration; 7 | import com.swirlds.metrics.api.Metrics; 8 | import java.io.IOException; 9 | import org.hiero.block.simulator.TestUtils; 10 | import org.junit.jupiter.api.Test; 11 | 12 | public class MetricsInjectionModuleTest { 13 | 14 | @Test 15 | void testProvideMetrics() throws IOException { 16 | Configuration configuration = TestUtils.getTestConfiguration(); 17 | 18 | // Call the method under test 19 | Metrics providedMetrics = MetricsInjectionModule.provideMetrics(configuration); 20 | 21 | assertNotNull(providedMetrics); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/java/org/hiero/block/simulator/mode/PublisherServerModeHandlerTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.simulator.mode; 3 | 4 | import static org.junit.jupiter.api.Assertions.assertThrows; 5 | import static org.mockito.Mockito.*; 6 | 7 | import org.hiero.block.simulator.grpc.PublishStreamGrpcServer; 8 | import org.hiero.block.simulator.mode.impl.PublisherServerModeHandler; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import org.mockito.Mock; 12 | import org.mockito.MockitoAnnotations; 13 | 14 | public class PublisherServerModeHandlerTest { 15 | 16 | @Mock 17 | private PublishStreamGrpcServer publishStreamGrpcServer; 18 | 19 | private PublisherServerModeHandler publisherServerModeHandler; 20 | 21 | @BeforeEach 22 | void setUp() { 23 | MockitoAnnotations.openMocks(this); 24 | publisherServerModeHandler = new PublisherServerModeHandler(publishStreamGrpcServer); 25 | } 26 | 27 | @Test 28 | void testConstructorWithNullArguments() { 29 | assertThrows(NullPointerException.class, () -> new PublisherServerModeHandler(null)); 30 | } 31 | 32 | @Test 33 | void testInit() { 34 | publisherServerModeHandler.init(); 35 | verify(publishStreamGrpcServer).init(); 36 | } 37 | 38 | @Test 39 | void testStop() throws InterruptedException { 40 | publisherServerModeHandler.stop(); 41 | verify(publishStreamGrpcServer).shutdown(); 42 | } 43 | 44 | @Test 45 | void testStop_throwsException() throws InterruptedException { 46 | doThrow(new InterruptedException("Test exception")) 47 | .when(publishStreamGrpcServer) 48 | .shutdown(); 49 | 50 | assertThrows(InterruptedException.class, () -> publisherServerModeHandler.stop()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000000.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000000.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000001.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000001.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000002.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000002.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000003.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000003.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000004.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000004.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000005.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000005.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000006.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000006.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000007.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000007.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000008.blk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiero-ledger/hiero-block-node/302fe30fc65686b73583ac5be70601c9f3588c87/tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/000000000000000000000000000000000008.blk -------------------------------------------------------------------------------- /tools-and-tests/simulator/src/test/resources/block-0.0.3-blk/notABlock.txt: -------------------------------------------------------------------------------- 1 | not a block, just ignore this file. 2 | -------------------------------------------------------------------------------- /tools-and-tests/suites/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { 3 | id("org.hiero.gradle.module.library") 4 | id("application") 5 | } 6 | 7 | description = "Hiero Block Node E2E Suites" 8 | 9 | application { 10 | mainModule = "org.hiero.block.suites" 11 | mainClass = "org.hiero.block.suites.BaseSuite" 12 | } 13 | 14 | mainModuleInfo { 15 | runtimeOnly("org.testcontainers.junit.jupiter") 16 | runtimeOnly("org.junit.jupiter.engine") 17 | runtimeOnly("org.junit.platform.launcher") 18 | runtimeOnly("org.testcontainers") 19 | runtimeOnly("com.swirlds.config.impl") 20 | } 21 | 22 | tasks.register("runSuites") { 23 | description = "Runs E2E Test Suites" 24 | group = "suites" 25 | 26 | // @todo(#813) All of the docker processing belongs here, not in block-node-app. 27 | // This might mean duplication, which is perfectly fine. 28 | dependsOn(":block-node-app:createDockerImage") 29 | 30 | useJUnitPlatform() 31 | testLogging { events("passed", "skipped", "failed") } 32 | testClassesDirs = sourceSets["main"].output.classesDirs 33 | classpath = sourceSets["main"].runtimeClasspath 34 | 35 | // Pass the block-node version as a system property 36 | systemProperty("block.node.version", project(":block-node-app").version.toString()) 37 | } 38 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | open module org.hiero.block.node.suites { 3 | requires com.swirlds.config.api; 4 | requires com.swirlds.config.extensions; 5 | requires org.hiero.block.protobuf.protoc; 6 | requires org.hiero.block.simulator; 7 | requires io.grpc; 8 | requires java.net.http; 9 | requires org.junit.jupiter.api; 10 | requires org.junit.platform.suite.api; 11 | requires org.testcontainers; 12 | requires static com.github.spotbugs.annotations; 13 | requires static dagger; 14 | } 15 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/block/access/BlockAccessTestSuites.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.block.access; 3 | 4 | import org.junit.platform.suite.api.SelectClasses; 5 | import org.junit.platform.suite.api.Suite; 6 | 7 | /** 8 | * Test suite for running block access tests, including both positive and negative test 9 | * scenarios. 10 | * 11 | *

This suite aggregates the tests from {@link GetBlockApiTests}. The {@code @Suite} 12 | * annotation allows running all selected classes in a single test run. 13 | */ 14 | @Suite 15 | @SelectClasses({GetBlockApiTests.class}) 16 | public class BlockAccessTestSuites {} 17 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/grpc/GrpcTestSuites.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.grpc; 3 | 4 | import org.hiero.block.suites.grpc.negative.NegativeServerAvailabilityTests; 5 | import org.hiero.block.suites.grpc.positive.PositiveEndpointBehaviourTests; 6 | import org.hiero.block.suites.grpc.positive.PositiveServerAvailabilityTests; 7 | import org.junit.platform.suite.api.SelectClasses; 8 | import org.junit.platform.suite.api.Suite; 9 | 10 | /** 11 | * Test suite for running gRPC server availability tests, including both positive and negative test 12 | * scenarios. 13 | * 14 | *

This suite aggregates the tests from {@link PositiveServerAvailabilityTests} and {@link 15 | * NegativeServerAvailabilityTests}. The {@code @Suite} annotation allows running all selected 16 | * classes in a single test run. 17 | */ 18 | @Suite 19 | @SelectClasses({ 20 | PositiveServerAvailabilityTests.class, 21 | PositiveEndpointBehaviourTests.class, 22 | NegativeServerAvailabilityTests.class 23 | }) 24 | public class GrpcTestSuites { 25 | 26 | /** 27 | * Default constructor for the {@link GrpcTestSuites} class. This constructor is empty as it 28 | * does not need to perform any initialization. 29 | */ 30 | public GrpcTestSuites() {} 31 | } 32 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/metrics/MetricsTestSuites.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.metrics; 3 | 4 | import org.junit.platform.suite.api.SelectClasses; 5 | import org.junit.platform.suite.api.Suite; 6 | 7 | /** 8 | * Test suite for running metrics-related tests. 9 | * 10 | *

This suite aggregates the tests from {@link MetricsCommonTests}. The {@code @Suite} 11 | * annotation allows running all selected classes in a single test run. 12 | */ 13 | @Suite 14 | @SelectClasses({ 15 | MetricsCommonTests.class, 16 | // Add other metrics test classes here as needed 17 | }) 18 | public class MetricsTestSuites {} 19 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/persistence/DataPersistenceTestSuites.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.persistence; 3 | 4 | import org.hiero.block.suites.persistence.positive.PositiveDataPersistenceTests; 5 | import org.junit.platform.suite.api.SelectClasses; 6 | import org.junit.platform.suite.api.Suite; 7 | 8 | /** 9 | * Test suite for running data persistence tests, including both positive and negative test 10 | * scenarios. 11 | * 12 | *

This suite aggregates the tests from {@link PositiveDataPersistenceTests}. The {@code @Suite} 13 | * annotation allows running all selected classes in a single test run. 14 | */ 15 | @Suite 16 | @SelectClasses({PositiveDataPersistenceTests.class}) 17 | public class DataPersistenceTestSuites { 18 | 19 | /** 20 | * Default constructor for the {@link DataPersistenceTestSuites} class. This constructor is 21 | * empty as it does not need to perform any initialization. 22 | */ 23 | public DataPersistenceTestSuites() {} 24 | } 25 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/publisher/PublisherTestSuites.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.publisher; 3 | 4 | import org.hiero.block.suites.publisher.positive.PositiveMultiplePublishersTests; 5 | import org.junit.platform.suite.api.SelectClasses; 6 | import org.junit.platform.suite.api.Suite; 7 | 8 | /** 9 | * Test suite for running multiple publishers tests, including both positive and negative test 10 | * scenarios. 11 | * 12 | *

This suite aggregates the tests from {@link PositiveMultiplePublishersTests}. The {@code @Suite} 13 | * annotation allows running all selected classes in a single test run. 14 | */ 15 | @Suite 16 | @SelectClasses({PositiveMultiplePublishersTests.class}) 17 | public class PublisherTestSuites { 18 | /** 19 | * Default constructor for the {@link org.hiero.block.suites.publisher.PublisherTestSuites} class. This constructor is 20 | * empty as it does not need to perform any initialization. 21 | */ 22 | public PublisherTestSuites() {} 23 | } 24 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/server/status/ServerStatusTestSuites.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.server.status; 3 | 4 | import org.hiero.block.suites.server.status.positive.PositiveServerStatusTests; 5 | import org.junit.platform.suite.api.SelectClasses; 6 | import org.junit.platform.suite.api.Suite; 7 | 8 | @Suite 9 | @SelectClasses({PositiveServerStatusTests.class}) 10 | public class ServerStatusTestSuites { 11 | /** 12 | * Default constructor for the {@link ServerStatusTestSuites} class.This constructor is 13 | * empty as it does not need to perform any initialization. 14 | */ 15 | public ServerStatusTestSuites() {} 16 | } 17 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/subscriber/SubscriberTestSuites.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.subscriber; 3 | 4 | import org.hiero.block.suites.subscriber.negative.NegativeSingleSubscriberTests; 5 | import org.hiero.block.suites.subscriber.positive.PositiveSingleSubscriberTests; 6 | import org.junit.platform.suite.api.SelectClasses; 7 | import org.junit.platform.suite.api.Suite; 8 | 9 | /** 10 | * Test suite for running subscriber tests, including both positive and negative test scenarios. 11 | * 12 | *

This suite aggregates the tests related to the subscriber functionality. The {@code @Suite} annotation allows running all selected classes in a single test run.

13 | */ 14 | @Suite 15 | @SelectClasses({PositiveSingleSubscriberTests.class, NegativeSingleSubscriberTests.class}) 16 | public class SubscriberTestSuites { 17 | /** 18 | * Default constructor for the {@link PositiveSingleSubscriberTests} class.This constructor is 19 | * empty as it does not need to perform any initialization. 20 | */ 21 | public SubscriberTestSuites() {} 22 | } 23 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/utils/ServerStatusUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.utils; 3 | 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | import org.hiero.block.api.protoc.BlockNodeServiceGrpc; 6 | import org.hiero.block.api.protoc.ServerStatusRequest; 7 | import org.hiero.block.api.protoc.ServerStatusResponse; 8 | 9 | public final class ServerStatusUtils { 10 | private ServerStatusUtils() { 11 | // Prevent instantiation 12 | } 13 | 14 | public static ServerStatusResponse requestServerStatus( 15 | @NonNull final BlockNodeServiceGrpc.BlockNodeServiceBlockingStub blockNodeServiceStub) { 16 | return blockNodeServiceStub.serverStatus( 17 | ServerStatusRequest.newBuilder().build()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tools-and-tests/suites/src/main/java/org/hiero/block/suites/verification/BlockVerificationTestSuites.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.suites.verification; 3 | 4 | import org.junit.platform.suite.api.SelectClasses; 5 | import org.junit.platform.suite.api.Suite; 6 | 7 | /** 8 | * Test suite for running block verification tests, including both positive and negative test 9 | * scenarios. 10 | * 11 | *

This suite aggregates the tests from {@link VerificationCommonTests}. The {@code @Suite} 12 | * annotation allows running all selected classes in a single test run. 13 | */ 14 | @Suite 15 | @SelectClasses({VerificationCommonTests.class}) 16 | public class BlockVerificationTestSuites {} 17 | -------------------------------------------------------------------------------- /tools-and-tests/tools/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | plugins { 3 | id("application") 4 | id("org.hiero.gradle.module.library") 5 | id("org.hiero.gradle.feature.legacy-classpath") // due to 'com.google.cloud.storage' 6 | id("org.hiero.gradle.feature.shadow") 7 | } 8 | 9 | description = "Hiero Block Stream Tools" 10 | 11 | application { mainClass = "org.hiero.block.tools.BlockStreamTool" } 12 | 13 | mainModuleInfo { 14 | requires("org.hiero.block.protobuf.pbj") 15 | requires("com.hedera.pbj.runtime") 16 | requires("com.github.luben.zstd_jni") 17 | requires("com.google.api.gax") 18 | requires("com.google.auth.oauth2") 19 | requires("com.google.cloud.core") 20 | requires("com.google.cloud.storage") 21 | requires("com.google.gson") 22 | requires("info.picocli") 23 | runtimeOnly("com.swirlds.config.impl") 24 | runtimeOnly("io.grpc.netty") 25 | } 26 | -------------------------------------------------------------------------------- /tools-and-tests/tools/src/main/java/org/hiero/block/tools/BlockStreamTool.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.tools; 3 | 4 | import org.hiero.block.tools.commands.BlockInfo; 5 | import org.hiero.block.tools.commands.ConvertToJson; 6 | import org.hiero.block.tools.commands.record2blocks.Record2BlockCommand; 7 | import org.hiero.block.tools.commands.record2blocks.gcp.AddNewerBlockTimes; 8 | import org.hiero.block.tools.commands.record2blocks.mirrornode.ExtractBlockTimes; 9 | import org.hiero.block.tools.commands.record2blocks.mirrornode.FetchMirrorNodeRecordsCsv; 10 | import org.hiero.block.tools.commands.record2blocks.mirrornode.ValidateBlockTimes; 11 | import picocli.CommandLine; 12 | import picocli.CommandLine.Command; 13 | 14 | /** 15 | * Command line tool for working with Hedera block stream files 16 | */ 17 | @SuppressWarnings("InstantiationOfUtilityClass") 18 | @Command( 19 | name = "subcommands", 20 | mixinStandardHelpOptions = true, 21 | version = "BlockStreamTool 0.1", 22 | subcommands = { 23 | ConvertToJson.class, 24 | BlockInfo.class, 25 | Record2BlockCommand.class, 26 | FetchMirrorNodeRecordsCsv.class, 27 | ExtractBlockTimes.class, 28 | ValidateBlockTimes.class, 29 | AddNewerBlockTimes.class 30 | }) 31 | public final class BlockStreamTool { 32 | 33 | /** 34 | * Empty Default constructor to remove JavaDoc warning 35 | */ 36 | public BlockStreamTool() {} 37 | 38 | /** 39 | * Main entry point for the app 40 | * @param args command line arguments 41 | */ 42 | public static void main(String... args) { 43 | int exitCode = new CommandLine(new BlockStreamTool()).execute(args); 44 | System.exit(exitCode); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tools-and-tests/tools/src/main/java/org/hiero/block/tools/commands/record2blocks/model/BlockTimes.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.tools.commands.record2blocks.model; 3 | 4 | import java.nio.ByteBuffer; 5 | import java.nio.LongBuffer; 6 | import java.nio.channels.FileChannel; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | import java.nio.file.StandardOpenOption; 10 | 11 | /** 12 | * Read the block times from the block_times.bin file. 13 | */ 14 | @SuppressWarnings("unused") 15 | public class BlockTimes { 16 | /** Mapped buffer on the block_times.bin file. */ 17 | private final LongBuffer blockTimes; 18 | 19 | /** 20 | * Load and map the block_times.bin file into memory. 21 | * 22 | * @param blockTimesFile the path to the block_times.bin file 23 | */ 24 | public BlockTimes(Path blockTimesFile) { 25 | try { 26 | // map file into bytebuffer 27 | final FileChannel fileChannel = FileChannel.open(blockTimesFile, StandardOpenOption.READ); 28 | final ByteBuffer blockTimesBytes = 29 | fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, Files.size(blockTimesFile)); 30 | fileChannel.close(); 31 | // wrap the ByteBuffer as a LongBuffer so we can easily read longs 32 | blockTimes = blockTimesBytes.asLongBuffer(); 33 | } catch (Exception e) { 34 | throw new RuntimeException(e); 35 | } 36 | } 37 | 38 | /** 39 | * Get the block time for the given block number. 40 | * 41 | * @param blockNumber the block number 42 | * @return the block time in milliseconds 43 | */ 44 | public long getBlockTime(int blockNumber) { 45 | return blockTimes.get(blockNumber); 46 | } 47 | 48 | /** 49 | * Get the maximum block number in the block_times.bin file. 50 | * 51 | * @return the maximum block number 52 | */ 53 | public long getMaxBlockNumber() { 54 | return blockTimes.capacity() - 1; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tools-and-tests/tools/src/main/java/org/hiero/block/tools/commands/record2blocks/model/ChainFileAndCount.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.hiero.block.tools.commands.record2blocks.model; 3 | 4 | /** 5 | * Simple Record for a ChainFile and the count of how many times there are similar chain files for a record file set. 6 | * 7 | * @param chainFile A chain file that is one of the common identical ones in a record file set 8 | * @param count The number of files that are identical in the record file set 9 | */ 10 | public record ChainFileAndCount(ChainFile chainFile, int count) {} 11 | -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | 0.14.0-SNAPSHOT --------------------------------------------------------------------------------