Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ dependencies {
implementation("io.spring.gradle:dependency-management-plugin:1.1.7")
implementation("org.apache.commons:commons-compress:1.27.1")
implementation("org.flywaydb:flyway-database-postgresql:11.10.3")
implementation("org.cyclonedx:cyclonedx-gradle-plugin:2.3.1")
implementation("org.graalvm.buildtools:native-gradle-plugin:0.11.0")
implementation("org.gradle:test-retry-gradle-plugin:1.6.2")
implementation("org.jooq:jooq-codegen-gradle:$jooqVersion")
implementation("org.jooq:jooq-meta:$jooqVersion")
Expand Down
26 changes: 13 additions & 13 deletions buildSrc/src/main/kotlin/docker-conventions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ plugins { id("com.bmuschko.docker-remote-api") }

val latest = "latest"

// Get the Docker images to tag by splitting dockerTag property and adding the project version
fun dockerImages(): Collection<String> {
val dockerRegistry: String by project
val dockerTag: String by project
val dockerImage = "${dockerRegistry}/hedera-mirror-${projectDir.name}:"
val customTags = dockerTag.split(',').map { dockerImage.plus(it) }
val versionTag = dockerImage.plus(project.version)
// Get the images to tag by splitting imageTag property and adding the project version
fun imageTags(): Collection<String> {
val imageRegistry: String by project
val imageTag: String by project
val image = "${imageRegistry}/hedera-mirror-${project.name}:"
val customTags = imageTag.split(',').map { image.plus(it) }
val versionTag = image.plus(project.version)
val tags = customTags.plus(versionTag).toMutableSet()

// Don't tag pre-release versions as latest
Expand All @@ -28,19 +28,19 @@ val dockerBuild =
tasks.register<DockerBuildImage>("dockerBuild") {
onlyIf { projectDir.resolve("Dockerfile").exists() }
buildArgs.put("VERSION", project.version.toString())
images.addAll(dockerImages())
images.addAll(imageTags())
inputDir = file(projectDir)
pull = true

val dockerPlatform: String by project
if (dockerPlatform.isNotBlank()) {
buildArgs.put("TARGETPLATFORM", dockerPlatform)
platform = dockerPlatform
val imagePlatform: String by project
if (imagePlatform.isNotBlank()) {
buildArgs.put("TARGETPLATFORM", imagePlatform)
platform = imagePlatform
}
}

tasks.register<DockerPushImage>("dockerPush") {
onlyIf { projectDir.resolve("Dockerfile").exists() }
dependsOn(dockerBuild)
images.addAll(dockerImages())
images.addAll(imageTags())
}
6 changes: 5 additions & 1 deletion buildSrc/src/main/kotlin/jooq-conventions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension
import org.flywaydb.core.Flyway
import org.testcontainers.containers.PostgreSQLContainer
import org.testcontainers.images.builder.Transferable
import org.testcontainers.utility.DockerImageName

plugins {
id("java-conventions")
Expand Down Expand Up @@ -68,8 +69,11 @@ val postgresqlContainer =
val initSh = "${dbDir}/scripts/init.sh"
doLast {
val initScript = Transferable.of(File(initSh).readBytes())
var image =
DockerImageName.parse("docker.io/library/postgres:16.9-alpine")
.asCompatibleSubstituteFor("postgres")
val container =
PostgreSQLContainer<Nothing>("postgres:16-alpine").apply {
PostgreSQLContainer<Nothing>(image).apply {
withCopyToContainer(initScript, "/docker-entrypoint-initdb.d/init.sh")
withUsername("postgres")
start()
Expand Down
21 changes: 18 additions & 3 deletions buildSrc/src/main/kotlin/spring-conventions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
id("com.gorylenko.gradle-git-properties")
id("docker-conventions")
id("java-conventions")
id("org.cyclonedx.bom")
id("org.graalvm.buildtools.native")
id("org.springframework.boot")
}

Expand All @@ -18,19 +20,32 @@

tasks.register("run") { dependsOn(tasks.bootRun) }

val imagePlatform: String by project
val platform = imagePlatform.ifBlank { null }

tasks.bootBuildImage {
val env = System.getenv()
val repo = env.getOrDefault("GITHUB_REPOSITORY", "hiero-ledger/hiero-mirror-node")
val image = "ghcr.io/${repo}"
val image = "ghcr.io/${repo}/${project.name}"

Check notice on line 29 in buildSrc/src/main/kotlin/spring-conventions.gradle.kts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

buildSrc/src/main/kotlin/spring-conventions.gradle.kts#L29

Redundant curly braces

buildpacks =
listOf(
"urn:cnb:builder:paketo-buildpacks/java",
"paketobuildpacks/health-checker",
"paketo-buildpacks/native-image",
)
docker {
imageName = image
imagePlatform = platform
publishRegistry {
password = env.getOrDefault("GITHUB_TOKEN", "")
username = env.getOrDefault("GITHUB_ACTOR", "")
}
tags = listOf("${image}:${project.version}")
publishRegistry { token = env["GITHUB_TOKEN"] }
}

environment =
mapOf(
"BP_HEALTH_CHECKER_ENABLED" to "true",
"BP_NATIVE_IMAGE_BUILD_ARGUMENTS" to
"--initialize-at-build-time=org.slf4j.helpers.Reporter,org.slf4j.LoggerFactory,ch.qos.logback",
"BP_OCI_AUTHORS" to "[email protected]",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,37 @@

package org.hiero.mirror.common;

import org.hibernate.cfg.AvailableSettings;
import org.hiero.mirror.common.config.CommonRuntimeHints;
import org.hiero.mirror.common.converter.CustomJsonFormatMapper;
import org.hiero.mirror.common.domain.SystemEntity;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;

@Configuration
@ConfigurationPropertiesScan("org.hiero.mirror")
@EnableConfigurationProperties(CommonProperties.class)
@EntityScan("org.hiero.mirror.common.domain")
@ImportRuntimeHints(CommonRuntimeHints.class)
public class CommonConfiguration {
@Bean
SystemEntity systemEntity(CommonProperties commonProperties) {
return new SystemEntity(commonProperties);
}

@Bean
HibernatePropertiesCustomizer hibernatePropertiesCustomizer() {
return p -> {
// Ensure Criteria API queries use bind parameters and not literals
p.put("hibernate.criteria.literal_handling_mode", "BIND");
p.put(AvailableSettings.GENERATE_STATISTICS, true);
p.put(AvailableSettings.HBM2DDL_AUTO, "none");
p.put(AvailableSettings.JSON_FORMAT_MAPPER, new CustomJsonFormatMapper());
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0

package org.hiero.mirror.common.config;

import com.github.benmanes.caffeine.cache.AsyncCacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.time.Instant;
import java.util.List;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;

public class CommonRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
// Caffeine loads generated cache implementations via reflection
registerCache(hints, "SSMSA");
registerCache(hints, "SSR");
registerCache(hints, "SSSMA");
registerCache(hints, "SSSMSA");
registerCache(hints, "SSSW");
registerNode(hints, "PSAMS");
registerNode(hints, "PSR");

// For ReconciliationJob.timestampStart use as an ID in Hibernate
hints.reflection().registerType(TypeReference.of(Instant[].class), MemberCategory.UNSAFE_ALLOCATED);
}

private void registerCache(RuntimeHints hints, String className) {
final var types = List.of(
TypeReference.of(Caffeine.class),
TypeReference.of(AsyncCacheLoader.class),
TypeReference.of("boolean"));
hints.reflection()
.registerType(
TypeReference.of("com.github.benmanes.caffeine.cache." + className),

Check warning on line 38 in common/src/main/java/org/hiero/mirror/common/config/CommonRuntimeHints.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

common/src/main/java/org/hiero/mirror/common/config/CommonRuntimeHints.java#L38

The String "com.github.benmanes.caffeine.cache." appears 2 times in the file.
b -> b.withConstructor(types, ExecutableMode.INVOKE));
}

private void registerNode(RuntimeHints hints, String className) {
hints.reflection()
.registerType(
TypeReference.of("com.github.benmanes.caffeine.cache." + className),
b -> b.withConstructor(List.of(), ExecutableMode.INVOKE));
}
}
64 changes: 21 additions & 43 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ required software, environment setup, IDE configurations, project compilation, a

To contribute to the mirror node project, you need to install the following software and tools:

### 1. **Java 21**
### Java 21

Requires **Java 21** or a later version for development.

- **Install Java 21**:

On Ubuntu and macOS:
On Ubuntu and macOS we recommend using [SDKMAN!](https://sdkman.io/) to manage JVM versions:

```bash
curl -s "https://get.sdkman.io" | bash
Expand All @@ -35,32 +35,10 @@ Requires **Java 21** or a later version for development.
sdk use java 21-tem
```

### 2. **Docker**
### Docker

Docker is used to manage and run containerized services (such as databases) for the mirror node.

- **Install Docker**:

On Ubuntu:

```bash
sudo apt update
sudo apt install docker.io
sudo systemctl enable docker --now
sudo usermod -aG docker $USER # Optional: allows non-root access
```

On macOS:

```bash
brew install --cask docker
open /Applications/Docker.app
```

- **Verify Installation**:
```bash
docker --version
```
Docker is used to manage and run containerized services (such as databases) for the mirror node. To install Docker,
follow the get started guide on [docker.com](https://docs.docker.com/get-started/get-docker/).

## Coding Standards

Expand All @@ -79,7 +57,7 @@ to follow:

## IDE Setup

We recommend using **IntelliJ IDEA** or **Eclipse** for development.
We recommend using **IntelliJ IDEA** for development.

### IntelliJ IDEA Setup

Expand Down Expand Up @@ -124,7 +102,8 @@ We recommend using **IntelliJ IDEA** or **Eclipse** for development.

## Compiling the Project

This project uses [Gradle](https://gradle.org) for building and managing dependencies.
This project uses [Gradle](https://gradle.org) for building and managing dependencies. It's not necessary to install
Gradle locally as the project automatically downloads it via the Gradle Wrapper.

1. **Clean and Build the Project**:
Run the following command to clean and build the project:
Expand Down Expand Up @@ -197,31 +176,30 @@ defined in `docker-compose` files within the repository.
docker compose down
```

## Generating Artifacts (Images)
## Container Images

For production or deployment, you may need to generate Docker images.
For production or deployment, you may need to generate container images.

1. **Build Docker Images**:
You can build Docker images using Gradle and specify custom properties to control the platform, registry, and tag for
the Docker image.
1. **Build Container Images**:
You can build container images using Gradle and specify custom properties to control the platform, registry, and tag.

```bash
./gradlew dockerBuild \
-PdockerPlatform=linux/amd64 \
-PdockerRegistry=docker.io \
-PdockerTag=1.0.0-SNAPSHOT
-PimagePlatform=linux/amd64 \
-PimageRegistry=docker.io/mydockerid \
-PimageTag=1.0.0-SNAPSHOT
```

2. **Push Docker Images**:
After building the Docker image, you can push it to the specified Docker registry to make it available for use in a
2. **Push Container Images**:
After building the container image, you can push it to the specified image registry to make it available for use in a
remote Kubernetes environment.

```bash
./gradlew dockerPush \
-PdockerPlatform=linux/amd64 \
-PdockerRegistry=docker.io \
-PdockerTag=1.0.0-SNAPSHOT
-PimagePlatform=linux/amd64 \
-PimageRegistry=docker.io \
-PimageTag=1.0.0-SNAPSHOT
```

NB: Ensure you are logged into the Docker registry if authentication is required. This command will push the image
Note: Ensure you are logged into the image registry if authentication is required. This command will push the image
with the specified tag to the registry.
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Project settings
dockerPlatform=
dockerRegistry=gcr.io/mirrornode
dockerTag=latest
imagePlatform=
imageRegistry=gcr.io/mirrornode
imageTag=latest
group="com.hedera"
lombok.disableConfig=true
maxParallelism=
Expand Down
8 changes: 2 additions & 6 deletions graphql/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,11 @@ spring:
graphql:
graphiql:
enabled: false
path: /graphql/alpha
http:
path: /graphql/alpha
jpa:
database: PostgreSQL
open-in-view: false
properties:
hibernate.criteria.literal_handling_mode: BIND # Ensure Criteria API queries use bind parameters and not literals
hibernate.generate_statistics: true
hibernate.hbm2ddl.auto: none
hibernate.type.json_format_mapper: org.hiero.mirror.common.converter.CustomJsonFormatMapper
lifecycle:
timeout-per-shutdown-phase: 20s
threads:
Expand Down
5 changes: 0 additions & 5 deletions grpc/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,6 @@ spring:
validation-timeout: 3000
jpa:
database: PostgreSQL
properties:
hibernate.criteria.literal_handling_mode: BIND # Ensure Criteria API queries use bind parameters and not literals
hibernate.generate_statistics: true
hibernate.hbm2ddl.auto: none
hibernate.type.json_format_mapper: org.hiero.mirror.common.converter.CustomJsonFormatMapper
lifecycle:
timeout-per-shutdown-phase: 40s
redis:
Expand Down
1 change: 1 addition & 0 deletions importer/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-cache")
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.retry:spring-retry")
implementation("org.springframework.cloud:spring-cloud-kubernetes-fabric8-leader")
implementation("org.springframework.cloud:spring-cloud-starter-bootstrap")
implementation("org.springframework.cloud:spring-cloud-starter-kubernetes-fabric8-config")
Expand Down
3 changes: 0 additions & 3 deletions importer/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,10 @@ spring:
hibernate:
hbm2ddl:
import_files_sql_extractor: org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor
generate_statistics: true
jdbc:
batch_size: 250
order_inserts: true
order_updates: true
type:
json_format_mapper: org.hiero.mirror.common.converter.CustomJsonFormatMapper
show-sql: false
lifecycle:
timeout-per-shutdown-phase: 20s
Expand Down
5 changes: 0 additions & 5 deletions rest-java/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,6 @@ spring:
jpa:
database: PostgreSQL
open-in-view: false
properties:
hibernate.criteria.literal_handling_mode: BIND # Ensure Criteria API queries use bind parameters and not literals
hibernate.generate_statistics: true
hibernate.hbm2ddl.auto: none
hibernate.type.json_format_mapper: org.hiero.mirror.common.converter.CustomJsonFormatMapper
lifecycle:
timeout-per-shutdown-phase: 20s
threads:
Expand Down
Loading
Loading