Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
23 changes: 19 additions & 4 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
tags = listOf("${image}:${project.version}")
publishRegistry { token = env["GITHUB_TOKEN"] }
imagePlatform = platform
publishRegistry {
password = env.getOrDefault("GITHUB_TOKEN", "")
username = env.getOrDefault("GITHUB_ACTOR", "")
}
tags = listOf("${image}:${project.version}2")

Check notice on line 44 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#L44

Redundant curly braces
}

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
Loading
Loading