Skip to content

Commit

Permalink
chore: update quickstart documentation (#12813)
Browse files Browse the repository at this point in the history
Signed-off-by: Jendrik Johannes <[email protected]>
  • Loading branch information
jjohannes authored Jun 13, 2024
1 parent 621c8fe commit a757df8
Show file tree
Hide file tree
Showing 25 changed files with 278 additions and 221 deletions.
25 changes: 7 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![codecov](https://codecov.io/gh/hashgraph/hedera-services/graph/badge.svg?token=ZPMV8C93DV)](https://codecov.io/gh/hashgraph/hedera-services)
[![Latest Version](https://img.shields.io/github/v/tag/hashgraph/hedera-services?sort=semver&label=version)](README.md)
[![Made With](https://img.shields.io/badge/made_with-java-blue)](https://github.com/hashgraph/hedera-services/)
[![Development Branch](https://img.shields.io/badge/docs-quickstart-green.svg)](hedera-node/docs/gradle-quickstart.md)
[![Development Branch](https://img.shields.io/badge/docs-quickstart-green.svg)](docs/gradle-quickstart.md)
[![License](https://img.shields.io/badge/license-apache2-blue.svg)](LICENSE)

# Hedera Services
Expand All @@ -14,27 +14,16 @@ Implementation of the Platform and the [services offered](https://github.com/has
nodes in the [Hedera public network](https://hedera.com).

## Overview of child modules
* _platform-sdk/_ - the basic Platform.
* _hedera-node/_ - implementation of Hedera services on the Platform.
* _platform-sdk/_ - the basic Platform[documentation](platform-sdk/docs/platformWiki.md)
* _hedera-node/_ - implementation of Hedera services on the Platform[documentation](hedera-node/docs/)

## JVM
An [Eclipse Adoptium](https://adoptium.net/) build of the Java 21 JDK is required. If an Adoptium JDK is not installed,
the Gradle build will download an appropriate Adoptium JDK. The JDK version used to execute Gradle must be Java 21+ in
order for the `checkAllModuleInfo` task to succeed.

## Solidity
Hedera Contracts support `pragma solidity <=0.8.9`.

## Docker Compose quickstart
## Getting Started

The [Docker quickstart](hedera-node/docs/docker-quickstart.md) covers how to
start a local network of Hedera Services nodes using Docker Compose.
Refer to the [Quickstart Guide](docs/README.md) for how to work with this project.

## Developer IntelliJ quickstart

The [IntelliJ quickstart](hedera-node/docs/intellij-quickstart.md) covers how to
start a local network of Services nodes from IntelliJ for testing and
development.
## Solidity
Hedera Contracts support `pragma solidity <=0.8.9`.

## Support

Expand Down
13 changes: 13 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Quickstart Guide

## Preliminaries: JDK

An [Eclipse Adoptium](https://adoptium.net/) build of the Java **21.0.1** JDK is required.

## Building, Running and Working with the project

- [Building, Testing and Running with Gradle](gradle-quickstart.md)
- [Developing with IntelliJ](intellij-quickstart.md)
- [Branch Naming Conventions](branch-naming-conventions.md)
- [Java Style Guide](hedera-java-style-guide.md)
- [Maintainers Guide](maintainers-guide.md)
File renamed without changes
Binary file added docs/assets/gradle-jdk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/gradle-reload.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/gradle-tasks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes.
174 changes: 174 additions & 0 deletions docs/gradle-quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Gradle quickstart

## Installation

The repo contains a `gradlew` (or `gradlew.bat` on windows) script. This script will automatically download
the right version of Gradle for this project, scoped to this project. This means you never need to have Gradle installed
manually on your computer. It also means, as the project updates to newer versions of Gradle, you will pick them up
automatically. And, the version of Gradle is checked in, meaning you will always have the right version for whatever
commit you are building from.

The only requirement to run Gradle is having a recent JDK installed. In order to ensure reproducible builds, this
project is configured to check the JDK you are currently using and fail if it does not correspond to the JDK you are
currently using. If you get an error, please download the indicated JDK and make sure the `java` command on your `PATH`
is of that JDK or that your `JAVA_HOME` is pointing at that JDK.

## Building the project

This documents explains how to use Gradle directly from the command line via the `./gradlew <task>` command.
All Gradle tasks can also be invoked from the Gradle view in [IntelliJ IDEA](intellij-quickstart.md).

There are several Gradle tasks you can use. Most notably:

- `./gradlew assemble` compile all code and create all Jar files
- `./gradlew qualityGate` in addition to the above, run all quality checks and auto-fix formatting where possible
- `./gradlew :<module-name>:<test-type>` run all tests in one module of the given [test type](#Testing).

You may run `./gradlew` (without arguments) for a detailed overview

## Running a services instance or example apps

- `./gradlew :app:modrun` runs a services instance
- `./gradlew :test-clients:runTestClient -PtestClient=com.hedera.services.bdd.suites.crypto.HelloWorldSpec`
- `./gradlew :swirlds-platform-base-example:run` runs Platform-base Example App

## Using Gradle during Development

### Changing or adding Modules of Hedera (aka Gradle Subprojects)

All modules are listed in [settings.gradle.kts](../settings.gradle.kts) using
`include(":<module-name>", "<module-folder-path>")`. The `module-folder-path` should be a folder in a subdirectory like
[platform-sdk](../platform-sdk) or [hedera-node](../hedera-node). In the folder, the following files are expected:

- `build.gradle.kts` specifies to which group of modules the module belongs, e.g.
`id("com.hedera.gradle.services")` or `id("com.hedera.gradle.platform")` and may contain
[dependency definitions](#changing-or-adding-dependencies) for tests.
- `src/main/java/module-info.java` is the Java Module specification that is also used to determine the
[dependencies of the module](#changing-or-adding-dependencies) by Gradle. Note that the last segment of the module name defined in
the `module-info.java` file needs to correspond to the name of the module defined in
[settings.gradle.kts](../settings.gradle.kts).

### Changing or Adding Dependencies

This project use of the _Java Module System (JPMS)_. With this, dependencies between modules are defined in the
`src/main/java/module-info.java` files that each module contains. Other modules are identified by their _Module Name_
there. For example, a dependency to the `swirlds-logging` module is expressed by `requires com.swirlds.logging`. A
dependency to the 3rd party library `com.fasterxml.jackson.core` is expressed by `requires com.fasterxml.jackson.core`.
Note: This project utilizes the
[org.gradlex.java-module-dependencies](https://github.com/gradlex-org/java-module-dependencies)
plugin to achieve this integration between Gradle and the Java Module System.

Each dependency definition contains a scope – e.g. `requires` or `requires transitive`. If you are unsure about a
scope, use `requires` when adding a dependency. Then execute `./gradlew qualityGate` which runs a dependency scope
check that analysis the code to determine which Java types are visible (and should be visible) to which modules. If
the check fails, it will advise you how to change the scope.

### Adding or Changing the Version of a 3rd party dependency

If you use a 3rd party module lke `com.fasterxml.jackson.core`, a version for that module needs to be selected.
For this, the [hedera-dependency-versions/build.gradle.kts](../hedera-dependency-versions/build.gradle.kts) defines a so-called _Gradle platform_ (also called BOM)
that contains the versions of all 3rd party modules used. If you want to upgrade the version of a module, do this here.
Remember to run `./gradlew qualityGate` after the change. If you need to use a new 3rd party module in a
`src/main/java/module-info.java` file, you need to add the version here. (If the new module is not completely Java
Module System compatible, you may also need to add [patching rules](#patching-3rd-party-modules)).

### Patching 3rd Party Modules

Some 3rd party libraries we use are not yet fully Java Module System compatible. And some modules pull in other
dependencies that we can neglect. Situations like this are treated as wrong/incomplete metadata in our Gradle
setup and the file
[com.hedera.gradle.jpms-modules.gradle.kts](../gradle/plugins/src/main/kotlin/com.hedera.gradle.jpms-modules.gradle.kts)
contains the rules to adjust or extend the metadata of 3rd party libraries to address such problems.

Note: This project utilizes the
[org.gradlex.extra-java-module-info](https://github.com/gradlex-org/extra-java-module-info)
and
[org.gradlex.jvm-dependency-conflict-resolution](https://gradlex.org/jvm-dependency-conflict-resolution/#resolution-plugin)
plugins to ease the definition of patching rules.

### Incrementing the Version of Hedera itself

Our Gradle build has a single version number for all modules. It is defined in [version.txt](../version.txt).
Changing this version number will automatically apply to every module.

### Testing

We have different types of tests, defined in different folders – so-called _source sets_ – in each module.

#### Unit Tests

- located in `src/main/test` of the corresponding module
- run with `./gradlew :<module-name>:test`

Unit tests will **always** be executed in PR builds and must pass before merging. The vast majority of
our tests should be unit tests (measured in the 10's of thousands). These tests are never flaky and should avoid
arbitrary waits and timeouts at all costs. The full body of unit tests should execute in roughly 5 minutes.

#### Integration Tests

- located in `src/main/itest` of the corresponding module
- run with `./gradlew :<module-name>:itest`

We define integration tests as those that involve several components, but not an entire working instance. These use
JUnit. Integration tests take longer to execute than unit tests. These should be the second most plentiful type of test.
They are designed to ensure two or more components work together. We recommend
using [Testcontainers](https://www.testcontainers.org/) for databases, mirror nodes, explorers, or other components that
live in different repos. These tests should be written carefully to avoid flakiness. If a test fails, it should
**always** mean that there is a real problem. Per module or subproject, integration tests should take no more than 10
minutes to execute. Across the entire repo, there should be thousands of integration tests.

Integration tests must **all pass** before merging to **main**, so they must be fast and reliable.

#### Hammer Tests

- located in `src/main/hammer` of the corresponding module
- run with `./gradlew :<module-name>:hammer`

A hammer test is a unit test that "hammers" the code. A more common and less visceral name for this type of test is a
"fuzzing" test. These usually take the form of pseudo-random tests that run for an extended period of time and attempt
to use a component in as many ways as possible.

Hammer tests by their nature take longer to execute. These are run on a nightly basis. They have concrete pass/fail
behavior. If any hammer test fails, this should mean there is **definitely** a bug that needs to be triaged.

#### Micro-benchmarks

- located in `src/main/jmh` of the corresponding module
- run with `./gradlew :<module-name>:jmh`

Micro-benchmarks are like the unit-tests of performance testing. They should be used liberally for establishing
metric-driven decisions about different designs. The specific numbers produced by a microbenchmark are not themselves
very useful because different hardware under different conditions can give different numbers. But they are useful when
comparing A/B implementations on the same hardware. These tests also take a significant amount of time to execute,
and are not very good at giving pass/fail criteria after execution.

Rather, micro-benchmarks exist to help developers verify the impact of their changes in a particular part of the system.
Appropriate benchmarks should be run prior to creation of a PR. These are run nightly, and we record the results, so
we can do trend analysis over time.

We use the [Java Micro-benchmarking Harness](https://github.com/openjdk/jmh), or JMH, for writing and executing our
micro-benchmarks.

#### End-to-End Tests

- located in `src/main/eet` of the `test-clients` module
- run with `./gradlew :test-clients:eet`

End-to-end tests need a running instance. You can start one in one terminal with `./gradlew modrun` and then execute
the tests from a second terminal with `./gradlew eet`. Or you can use JRS to start an instance, or use some existing
environment.

### Cleaning

Gradle projects put all build artifacts into `build` directories. To clean your workspace of all these build artifacts,
use `./gradlew clean`. Note: cleaning is not necessary to get correct built results. You only need to do it if you want
to free disc space.

## Changing details in the Gradle setup

Generally, Gradle is configured through so-called Gradle _convention plugins_. A convention plugin is a plugin that
applies a certain set of defaults to all builds that include that convention. We define one such plugins in
[gradle/plugins/src/main/kotlin](../gradle/plugins/src/main/kotlin) using Gradle's Kotlin DSL notation.
If you need to adjust something in the build itself, this is the places where all configuration is located.
For details, see comments in the existing convention plugins (`*.gradle.kts` files).

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
# IntelliJ quickstart

## JVM

OpenJDK17 is strongly recommended. You can [download it from IntelliJ](https://www.jetbrains.com/help/idea/sdk.html)
if you don't have it already.

## Preliminaries

Clone this repository:
Expand All @@ -15,63 +10,78 @@ git clone https://github.com/hashgraph/hedera-services.git

From IntelliJ, choose `File -> Open` the _hedera-services/_ directory you just cloned.

Make sure you are using JDK17 as the project SDK:

<p>
<img src="assets/jdk-17.png"/>
</p>
### (optional) IntelliJ plugins

Run the Gradle `assemble` task in the root project (for example, via the IntelliJ Gradle tool window).
The following plugins add comfort features for working with certain parts of the code base:

This will both,
<ol>
<li>Build the <i>hedera-node/data/apps/HederaNode.jar</i>; and,
<li>Populate your <i>hedera-node/data/config</i> directory with
dev-appropriate versions of the <i>application.properties</i>,
<i>api-permission.properties</i>, and <i>node.properties</i>
files that are used to bootstrap a new Hedera Services network.
(To read more about how properties are sourced in Services,
please see [here](./services-configuration.md).)
</ol>
- [Android IntelliJ plugin](https://plugins.jetbrains.com/plugin/22989-android)
adds additional code navigation capabilities for Dagger2 annotated interfaces.
- [JMH IntelliJ plugin](https://plugins.jetbrains.com/plugin/7529-jmh-java-microbenchmark-harness)
allows running selected JMH benchmarks directly from the IDE.

## Starting a local single-node network
## Configure the JDK used by Gradle

Now browse to `com.hedera.node.app.ServicesMain`. Its
`main` method starts a single node network of Hedera Service by
calling `com.swirlds.platform.Browser#main`, which is the
entrypoint to bootstrap the Platform app named by the
[_config.txt_](../hedera-node/config.txt) in the working
directory.
The project is imported as a Gradle project. Before you can use all features reliably, make sure that Gradle is
started with the JDK we use in the project, which currently is:
**Eclipse Temurin, 21.0.1**

Run `ServicesMain#main` with an IntelliJ configuration whose working
directory is the _hedera-node/_ directory of your clone of this repo:
You can use IntelliJ to download the JDK if you do not have it installed.

<p>
<img src="./assets/node-config.png" height="518" width="800" />
<img src="./assets/gradle-jdk.png" />
</p>

You can also run from Gradle below:

## Reload Project with Gradle

After everything is configured, and everytime you change something in the project setup, you should press the
**Reload All Gradle project** in IntelliJ.

Changes to the project setup include,
- Changing `build.gradle.kts` files
- Changing dependencies in `src/main/java/module-info.java` files
- Changing build configuration in `gradle/plugins/src/main/kotlin`

<p>
<img src="./assets/gradle-run.png" height="214" width="415" />
<img src="./assets/gradle-reload.png" />
</p>

You will see a single black pane appear, similar to:
See [gradle-quickstart](gradle-quickstart.md) for more details on modifying the project setup.

## Build, test, run through Gradle tasks

You can run all tasks described in [gradle-quickstart](gradle-quickstart.md) from the Gradle tool window.

<p>
<img src="./assets/node-startup.png" height="150" width="600"/>
<img src="./assets/gradle-tasks.png" />
</p>

This node's name is "Alice" because of [Line 26](../hedera-node/config.txt#L26)
## Running a services instance or example apps

### Starting a local single-node network

You can start the `ServicesMain` process via the `modrun` Gradle task. You will see an output like the following:

```
2024-04-25 11:00:26.066 INFO 169 NettyGrpcServerManager - Starting gRPC server on port 50211
2024-04-25 11:00:26.118 INFO 292 NettyGrpcServerManager - Epoll not available, using NIO
2024-04-25 11:00:26.172 INFO 172 NettyGrpcServerManager - gRPC server listening on port 50211
2024-04-25 11:00:26.172 INFO 180 NettyGrpcServerManager - Starting TLS gRPC server on port 50212
2024-04-25 11:00:26.172 INFO 292 NettyGrpcServerManager - Epoll not available, using NIO
2024-04-25 11:00:26.172 WARN 325 NettyGrpcServerManager - Specified TLS cert 'hedera.crt' doesn't exist!
2024-04-25 11:00:26.173 WARN 187 NettyGrpcServerManager - Could not start TLS server, will continue without it: hedera.crt
```

This node's name is "Alice" because of [Line 25](../hedera-node/config.txt#L25)
in the _config.txt_ present in your working directory.

Looking closer at _config.txt_, you can see you are running Hedera Services
(and not some other app) because [Line 12](../hedera-node/config.txt#L12)
(and not some other app) because [Line 11](../hedera-node/config.txt#L11)
points to the JAR file you just built; and there are three nodes in your
network because you specified "Bob" and "Carol" as well as "Alice".

If multiple nodes Alice, Bob, and Carol are set up to run locally by
uncommenting lines [27](../hedera-node/config.txt#L27) and [29](../hedera-node/config.txt#L29),
uncommenting lines [26](../hedera-node/config.txt#L26) and [28](../hedera-node/config.txt#L28),
they will all be running on your local machine; and
communicating via the loopback interface. But each still has a private
instance of the Platform, and keeps its own state, just as it would in a
Expand All @@ -90,19 +100,18 @@ Public: 0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92
Private: 91132178e72057a1d7528025956fe39b0b847f200ab59b2fdd367017f3087137
```

## Submitting transactions to your local network
### Submitting transactions to your local network

The _test-clients/_ directory in this repo contains a large number of
end-to-end tests that Hedera engineering uses to validate the behavior of
Hedera Services. Many of these tests are written in the style of a BDD
specification.

Run `HelloWorldSpec#main` with an IntelliJ configuration whose working
directory is the _test-clients/_ directory of your clone of this repo:
Run `HelloWorldSpec` with the following Gradle command:

<p>
<img src="./assets/spec-configuration.png" height="300" width="450" />
</p>
```
./gradlew runTestClient -PtestClient=com.hedera.services.bdd.suites.crypto.HelloWorldSpec
```

Because [`node=localhost`](../test-clients/src/main/resource/spec-default.properties)
in the _spec-default.properties_ controlling the `HelloWorldSpec` test, this
Expand All @@ -123,9 +132,9 @@ will run against your local network, culminating in logs similar to:
keypair via its configuration in [_spec-default.properties_](../test-clients/src/main/resource/spec-default.properties)
under the `startupAccounts.path` key).

## Stopping/restarting the network
### Stopping/restarting the network

Stop the `ServicesMain` process in IntelliJ to shut down the network.
Stop the `ServicesMain` process by stopping the `modrun` Gradle run.

When you restart `ServicesMain`, the nodes will attempt to restore their
state from the _hedera-node/data/saved_ directory tree.
Expand Down
Loading

0 comments on commit a757df8

Please sign in to comment.