# Blockchain in Java

- Link: https://ultimasolution.pl/blockchain-in-java/
- Published: 2026-04-10T09:06:15+02:00
- Author: Karol Preiskorn

## Blockchain in Java

[⌊Java 21⌉⌊Java 21⌉[ [⌊Gradle 8.10.2⌉](https://gradle.org/) [⌊JUnit 5⌉](https://junit.org/junit5/) [⌊License⌉](https://ultimasolution.pl/blockchain-in-java/#attribution)

A focused Java implementation of a learning-oriented blockchain, covering blocks,
proof of work, wallets, signed transactions, UTXO accounting, and chain validation.

> Educational project: this implementation demonstrates blockchain concepts and 
> is not intended for production financial use.

## Contents

 * [Overview](https://ultimasolution.pl/blockchain-in-java/#overview)
 * Architecture
 * Key implementation areas
 * [Running the project](https://ultimasolution.pl/blockchain-in-java/#running-the-project)
 * [Testing](https://ultimasolution.pl/blockchain-in-java/#testing)
 * Project structure
 * [Contributing](https://ultimasolution.pl/blockchain-in-java/#contributing)
 * [Useful links](https://ultimasolution.pl/blockchain-in-java/#useful-links)

## Overview

This repository contains:

 * a simplified blockchain implementation in Java
 * wallet and transaction logic based on public-key cryptography
 * UTXO-style accounting with unspent transaction outputs

This project is intentionally defined as a blockchain learning demo. It models the
core ideas of linked blocks, UTXO accounting, signatures, and validation without
pretending to be a production blockchain node or a secure financial system.

## Assumptions and scope

The implementation is intentionally constrained to make the concepts easy to study:

 * blocks are linked by a hash chain and a simple proof-of-work target
 * transactions are signed with ECDSA keys and checked against wallet ownership
 * balances are derived from the ledger’s unspent outputs, not from floating-point
   state
 * transaction and output validation is strict enough to reject malformed inputs,
   negative values, and impossible spending patterns
 * the project does not simulate peer-to-peer networking or consensus across independent
   nodes

This is a teaching-oriented model, not a real-world blockchain deployment.

## Architecture

The main flow connects wallets, signed transactions, blocks, and the UTXO ledger.
Validation checks the resulting chain and transaction relationships.

    ```mermaid
    flowchart LR
    	WalletA[Wallet] -->|signs| Transaction[Transaction]
    	WalletB[Wallet] -->|receives| Transaction
    	Transaction -->|included in| Block[Block]
    	Block -->|linked by hash| Blockchain[Blockchain]
    	Blockchain --> Ledger[BlockchainLedger / UTXOs]
    	Ledger -->|calculates| Balance[Wallet balance]
    	Blockchain --> Validator[BlockchainValidator]
    	Validator -->|checks| Block
    	Validator -->|checks| Transaction
    ```

The detailed design is documented in BLOCKCHAIN.md.

## Project status

 * Java toolchain: 21
 * Gradle: 8.10.2
 * Test framework: JUnit 5.12.2
 * Server framework: Spring Boot 4.2.0-M1
 * Crypto library: Bouncy Castle 1.85.2
 * Serialization: Gson 2.14.0
 * Formatting: Spotless 8.10.2
 * Dependency update reporting: Gradle Versions Plugin 0.61.0

## Project identity and professional quality bar

This repository is intentionally scoped as a blockchain learning demo, not as a 
production payment network. The professional standard here is clarity, correctness,
and explicit boundaries rather than production-grade security guarantees.

The project deliberately keeps the following rules:

 * the domain package contains blockchain logic only
 * the demo package contains scenario orchestration and examples
 * balance rules are derived from UTXOs rather than floating-point state
 * validation stays explicit and easy to read
 * block and transaction state is private, with read-only views and controlled mutation
   methods
 * transaction inputs and outputs are private value objects with controlled resolution
   and accessors
 * the ledger is read-only outside the blockchain aggregate
 * Merkle roots are checked against block transactions
 * accepted blocks and transactions are sealed against later mutation
 * unsupported production concerns such as networking, persistence, consensus, and
   wallet storage remain outside scope

This keeps the implementation educational while still behaving like a maintainable
Java project.

## Key implementation areas

### Domain layer

The blockchain engine and core model live under the domain package:

 * [src/main/java/blockchain/domain/Blockchain.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/Blockchain.java)—
   blockchain state and block storage
 * [src/main/java/blockchain/domain/Block.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/Block.java)—
   individual block model
 * [src/main/java/blockchain/domain/Transaction.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/Transaction.java)—
   transaction logic and validation
 * [src/main/java/blockchain/domain/TransactionInput.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/TransactionInput.java)—
   spending references
 * [src/main/java/blockchain/domain/TransactionOutput.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/TransactionOutput.java)—
   unspent output representation
 * [src/main/java/blockchain/domain/Wallet.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/Wallet.java)—
   key generation, balance lookup, and fund transfers
 * [src/main/java/blockchain/domain/BlockchainValidator.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/BlockchainValidator.java)—
   validation rules for chain integrity
 * [src/main/java/blockchain/domain/BlockchainLedger.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/BlockchainLedger.java)—
   UTXO ledger and balance calculations
 * [src/main/java/blockchain/domain/StringUtil.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/StringUtil.java)—
   hashing and string helpers
 * [src/main/java/blockchain/domain/ValidationResult.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/domain/ValidationResult.java)—
   structured validation outcomes

### Demo layer

The runnable examples and scenario setup live under the demo package:

 * [src/main/java/blockchain/demo/SimpleBlockchain.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/demo/SimpleBlockchain.java)—
   main blockchain demo with mining and transfer flow
 * [src/main/java/blockchain/demo/BlockchainDemo.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/demo/BlockchainDemo.java)—
   alternate demo/example app
 * [src/main/java/blockchain/demo/BlockchainScenario.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/demo/BlockchainScenario.java)—
   reusable demo scenario orchestration
 * [src/main/java/blockchain/demo/BlockchainCli.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/demo/BlockchainCli.java)—
   command-line entry point handling
 * [src/main/java/blockchain/demo/DemoOptions.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/java/blockchain/demo/DemoOptions.java)—
   validated demo parameters

## Running the project

### Build

    ```bash
    ./gradlew build
    ```

Every push to `master` and every pull request runs the same Gradle build and Docker
image build through GitHub Actions. The workflow uses Java 21 and includes tests,
Spotless checks, packaging, and the Dockerfile build.

### Run the app

    ```bash
    ./gradlew run
    ```

The demo also accepts a few command-line options so the learning scenario can be
explored without changing source code:

    ```bash
    ./gradlew run --args="--difficulty=2 --initial-balance=150 --first-transfer=35 --second-transfer=10"
    ./gradlew run --args="--difficulty=2 --minimum-transaction=1"
    ./gradlew run --args="--help"
    ```

The CLI controls only the demo scenario. It does not change the domain rules or 
turn this project into a production node.

The scenario deliberately includes both successful and rejected transfers. Rejected
transfers are reported without terminating the demo, so insufficient funds and validation
behavior can be observed safely. Accepted blocks print their hash, parent hash, 
Merkle root, nonce, and transaction totals. The final summary reports block count,
transaction count, UTXO count and details, cumulative proof-of-work, chain tip, 
and validation status.

### Run the HTTP API

Start the Spring Boot server with the in-memory learning chain:

    ```bash
    ./gradlew bootRun
    ```

The first API slice is available under `/api/v1`:

    ```EnlighterJSRAW
    curl http://localhost:8080/api/v1/blockchain/info 
    curl http://localhost:8080/api/v1/blocks 
    curl http://localhost:8080/api/v1/utxos 
    curl http://localhost:8080/api/v1/blockchain/validate 
    curl http://localhost:8080/api/v1/wallets 
    curl http://localhost:8080/api/v1/transactions 
    curl -X POST http://localhost:8080/api/v1/blocks/mine
    ```

Register a client public key with `POST /api/v1/wallets`, then submit a client-signed
transaction with `POST /api/v1/transactions`. The request contains Base64-encoded
EC public keys, input output IDs, and a Base64-encoded ECDSA signature; private 
keys are never accepted by this server. State-changing requests are protected by
a cookie-backed CSRF token. Submitted transactions remain pending until `POST /api/
v1/blocks/mine` is called.

This server is single-node. The default profile is in-memory for quick learning;
the `postgres` profile persists and restores chain state and pending transactions.
The versioned HTTP contract is maintained in `openapi.yaml`.

The persistence foundation is included for local development. Start PostgreSQL with:

    ```bash
    docker compose up -d postgres
    ```

The `postgres` Spring profile enables the database connection and Flyway migrations:

    ```bash
    SPRING_PROFILES_ACTIVE=postgres ./gradlew bootRun
    ```

Flyway applies [V1__create_blockchain_schema.sql](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/resources/db/migration/V1__create_blockchain_schema.sql),
which creates tables for chain metadata, blocks, transactions, inputs, outputs, 
wallets, and pending transactions. Add future schema changes as ordered migrations
beneath `src/main/resources/db/migration`. The PostgreSQL profile loads existing
state on startup, validates the reconstructed chain, and persists accepted state
changes atomically.

Run the complete API and database stack with Docker:

    ```bash
    docker compose up --build
    ```

The API container exposes `/actuator/health` and waits for PostgreSQL before starting.
The image uses a deterministic `java-blockchain.jar` artifact and includes `curl`
for its container healthcheck.

Then query the API:

    ```bash
    curl http://localhost:8080/api/v1/blockchain/info
    curl http://localhost:8080/actuator/health
    ```

The endpoint contract is available at [openapi.yaml](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/main/resources/openapi.yaml).
It documents request/response shapes, CSRF-protected state-changing operations, 
and the current single-node semantics. Generated Swagger UI is intentionally not
included yet.

Invalid domain requests, validation failures, and malformed JSON return RFC 7807-
style Problem Details with a stable `type` property for client-side handling.

Stop the stack while preserving the database volume with `docker compose down`. 
Use `docker compose down -v` when you want a clean learning chain.

### Run tests

    ```bash
    ./gradlew test
    ```

### Check for dependency updates

The Gradle Versions Plugin reports available updates without changing project files:

    ```bash
    ./gradlew dependencyUpdates
    ```

The report is written to `build/dependencyUpdates/report.txt`. Review each candidate
before changing `build.gradle`, then run the complete verification workflow:

    ```EnlighterJSRAW
    ./gradlew clean build --refresh-dependencies 
    /home/karol/.local/share/snyk-ls/snyk-linux test 
    /home/karol/.local/share/snyk-ls/snyk-linux code test
    ```

Security-sensitive dependencies should be upgraded individually so regressions are
easy to identify. Bouncy Castle must remain on a supported, non-vulnerable release.

### Use the Makefile shortcuts

    ```EnlighterJSRAW
    make help 
    make build 
    make test 
    make run 
    make clean
    ```

## Testing

The project includes JUnit-based checks for wallet behavior, cryptography, and balance-
related logic. The tests live in:

 * [src/test/java/blockchain/WalletTest.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/test/java/blockchain/WalletTest.java)
 * src/test/java/blockchain/BlockTest.java
 * [src/test/java/blockchain/BlockchainIntegrationTest.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/test/java/blockchain/BlockchainIntegrationTest.java)
 * [src/test/java/blockchain/BlockchainBehaviorContractTest.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/test/java/blockchain/BlockchainBehaviorContractTest.java)
 * [src/test/java/blockchain/TransactionModelValidationTest.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/test/java/blockchain/TransactionModelValidationTest.java)
 * [src/test/java/blockchain/DemoOptionsTest.java](https://github.com/karol-preiskorn/java-blockchain/blob/master/src/test/java/blockchain/DemoOptionsTest.java)
 * src/test/java/blockchain/BlockchainApiTest.java

## Blockchain design notes

This project follows a simplified blockchain model inspired by classic blockchain
tutorials, with explicit integrity rules:

 * each block contains a hash and a previous hash
 * transactions are signed with ECDSA keys
 * UTXOs represent available spendable value
 * balances are computed from wallet-owned outputs
 * funds are sent only when the wallet has enough unspent value
 * transaction signatures cover the canonical sender, recipient, amount, and input
   references
 * transaction and output IDs are checked against their canonical contents
 * rejected blocks restore both the ledger and transaction object state
 * block acceptance returns structured validation results for explainable rejection
 * valid chains expose cumulative proof-of-work for chain comparison

Important implementation detail: the project uses BigDecimal for monetary values
instead of float/double, which avoids precision problems in transaction arithmetic.

## Project structure

    ```project-tree
    java-blockchain/
    ├── README.md
    ├── BLOCKCHAIN.md
    ├── AGENT.md
    ├── Dockerfile
    ├── docker-compose.yml
    ├── .dockerignore
    ├── Makefile
    ├── build.gradle
    ├── settings.gradle
    ├── gradlew
    ├── src/
    │   ├── main/java/
    │   │   └── blockchain/
    │   │       ├── BlockchainApplication.java
    │   │       ├── api/
    │   │       ├── config/
    │   │       ├── demo/
    │   │       ├── domain/
    │   │       ├── persistence/
    │   │       └── service/
    │   ├── main/resources/
    │   │   ├── application.yml
    │   │   ├── application-postgres.yml
    │   │   ├── openapi.yaml
    │   │   └── db/migration/
    │   │       └── V1__create_blockchain_schema.sql
    │   └── test/java/
    │       └── blockchain/
    └── gradle/
    ```

## Domain vs demo

The repository intentionally separates the two concerns:

 * the domain package contains the blockchain engine itself: blocks, transactions,
   wallets, validation, and the ledger
 * the demo package contains scenario setup and console examples that exercise the
   domain model

This keeps the educational project easy to read: the engine stays focused on blockchain
rules, while the demo layer remains a thin, human-friendly entry point.

The runtime path is:

    ```mermaid
    flowchart LR
    	CLI[BlockchainCli] --> Options[DemoOptions]
    	Options --> Scenario[BlockchainScenario]
    	Scenario --> Domain[blockchain.domain]
    	Domain --> Output[Console output]
    ```

## Notes

This repository is a focused learning-oriented Java blockchain implementation. It
emphasizes clear state modeling, dependency hygiene, explicit validation, and a 
clean separation between the blockchain domain and its runnable demo. Repository-
specific working conventions are documented in [AGENT.md](https://github.com/karol-preiskorn/java-blockchain/blob/master/AGENT.md).

## Production-readiness note

This project is intentionally not production-ready. It is designed for learning,
experimentation, and code review. It does not include peer-to-peer networking, consensus
across multiple nodes, secure key storage, persistent storage, mempool management,
or production-grade security hardening. Values should never be treated as real currency
or transferred outside a controlled educational environment.

## Contributing

Small, focused improvements are welcome. Before opening a change:

 1. Keep the example-oriented scope of the project in mind.
 2. Add or update tests for behavioral changes.
 3. Run `./gradlew test` and `./gradlew build` locally.
 4. Update the relevant markdown documentation when public behavior or project structure
    changes.
 5. Keep the code readable and easy to reason about for learners; favor clear names
    and obvious validation over clever shortcuts.

Please do not treat the demo cryptography, key handling, or transaction model as
production-ready security code.

For a short project workflow, see CONTRIBUTING.md.

## Changelog

The project history is tracked in CHANGELOG.md.

## Useful links

 * BLOCKCHAIN.md — blockchain architecture notes
 * [https://gradle.org](https://gradle.org) — Gradle build system
 * [https://www.bouncycastle.org](https://www.bouncycastle.org) — cryptography provider

## Attribution

The blockchain examples were originally inspired by publicly available Java blockchain
tutorials. The current repository includes additional refactoring, tests, and project-
specific examples.
