High-Performance Modular Blockchain Framework Powered by Kotlin with Proof of Stake
Kokonut is a lightweight and scalable blockchain framework written in Kotlin. Designed for educational and research purposes, it implements Proof of Stake (PoS) consensus with core blockchain principles (Staking, Validation, Wallets) using an intuitive multi-module architecture.
- β‘ Proof of Stake (PoS): Energy-efficient consensus mechanism - no wasteful mining
- π StakeVault Staking: Stake KNT by locking funds to the on-chain stakeVault
- π Stake-Weighted Selection: Validators selected probabilistically based on stake amount
- π IPv6 P2P: Direct peer-to-peer connectivity without NAT/port forwarding
- π― Treasury-Paid Rewards (B-model): Validator rewards are recorded as treasury-paid on-chain transactions
- π Validator Onboarding Reward: On first successful Light Node connect, the network records a 2 KNT onboarding payout (1 KNT to the Full Node reward receiver, 1 KNT to the validator)
- π Enhanced Chain Integrity: Strict previousHash validation and timestamp consistency for blockchain security
- π° Smart Deposit Management: Automatic deposit returns after staking completion with transaction logging
This project is organized as a Gradle multi-module project, where each module plays a distinct role in the blockchain network.
Contains the core blockchain framework with a clean, minimal architecture:
library/src/main/kotlin/kokonut/
βββ core/ # Core blockchain data structures
β βββ Block.kt
β βββ BlockChain.kt
β βββ Data.kt
β βββ FuelNodeInfo.kt
β βββ NetworkRules.kt
β βββ NodeHandshake.kt
β βββ Policy.kt
β βββ Transaction.kt
β βββ Validator.kt
β βββ ValidatorOnboardingInfo.kt
βββ state/ # State management
β βββ NodeState.kt
β βββ ValidatorState.kt
βββ util/ # Utilities and API
βββ API.kt
βββ FullNode.kt
βββ GenesisGenerator.kt
βββ NodeType.kt
βββ Router.kt
βββ SQLite.kt
βββ Utility.kt
βββ ValidatorPool.kt
βββ ValidatorSession.kt
βββ Wallet.kt
core/: Core blockchain entities (Block, BlockChain, Transaction, Validator)state/: Node and validator state enumsutil/: HTTP API, routing, utilities, and wallet management
Acts as the network entry point and provides Node Discovery services.
- Genesis Block: Distributes the initial block (Genesis Block) to Full Nodes.
- Node Discovery: Manages and propagates the list of Full Nodes participating in the network.
- Policy: Manages network policies.
The core node that maintains and operates the actual blockchain network.
- Validation: Validates and creates new blocks using Proof of Stake (no energy-intensive mining).
- Staking: Validators stake by locking KNT to the stakeVault (on-chain).
- Block Production: Selected validators create blocks based on stake weight.
- Propagation: Propagates new blocks to other nodes.
- API Server: Provides an HTTP API for external monitoring of chain status.
A desktop wallet application for users (built with Compose Desktop).
- Wallet Management: Login via
.pemkey files. - Staking Operations: Seamless staking workflow with automatic deposit management
- Start Staking: Automatically calls
/stakeLockif needed before validation - Stop Staking: Gracefully stops validation, syncs chain, and updates balance
- Start Staking: Automatically calls
- Balance Updates: Real-time balance updates after block validation and rewards
- Transaction Recording: Accurate transaction logging for all staking operations
- Monitoring: Check validating status and wallet address (Validator ID)
Requirement: Kokonut requires Java 17 or higher.
- Java JDK 17 or higher
- Kotlin 2.1.0 (Included in Gradle settings)
Run the following command in the project root to build the entire project.
# Windows
./gradlew.bat build
# Mac/Linux
./gradlew buildEach node can be run individually. The recommended order is Fuel Node β Full Node (Multiple) β Light Node.
./gradlew.bat :fuelnode:run- The server starts on
http://[::]:80(Dual Stack IPv4/IPv6) by default. - Note on IPv6: When connecting via IPv6, enclose the address in brackets (e.g.,
http://[2001:db8::1]:80). - IPv6 Priority: This project prioritizes IPv6 for direct peer-to-peer connectivity without NAT. While the server binds to
::(dual stack), IPv4-only clients may experience limitations in P2P scenarios.
./gradlew.bat :fullnode:runFull Nodes must join an existing network:
- Set
KOKONUT_PEERto a reachable Fuel Node or peer Full Node (e.g.,http://<FUEL_NODE_IP>:80).
Optional:
- Set
KOKONUT_FULLNODE_REWARD_RECEIVERto control where the onboarding reward is credited for the Full Node (defaults to the Full Node's own URL as seen by the server). - Set
KOKONUT_ADVERTISE_ADDRESSto the publicly reachable base URL for this Full Node (used as the source address for propagation so other Full Nodes can pull your chain correctly). - Set
KOKONUT_TREASURY_ADDRESSto override the treasury address (default:KOKONUT_TREASURY). - Set
KOKONUT_STAKE_VAULT_ADDRESSto override the stake vault address (default:KOKONUT_STAKE_VAULT).
./gradlew.bat :lightnode:run- A GUI window will appear. Load your
.pemkey files to log in.
Full Nodes and the Fuel Node interact via HTTP APIs.
| Method | Endpoint | Description |
|---|---|---|
GET |
/ |
Node status and information dashboard (HTML) |
POST |
/handshake |
Client handshake (returns network info) |
GET |
/getLastBlock |
Get the last block of the current chain |
GET |
/getChain |
Get the entire blockchain data |
GET |
/getBalance?address= |
Get wallet balance for a given address (returns JSON) |
GET |
/isValid |
Check the integrity of the local blockchain |
GET |
/getTotalCurrencyVolume |
Get the total supply of KNT |
GET |
/getReward |
Get the current reward policy value |
GET |
/getValidators |
Get the current validator set |
POST |
/stakeLock |
Lock stake to stakeVault (creates on-chain STAKE_LOCK block) |
POST |
/startValidating |
Register a validator session (requires stake >= minimum) |
POST |
/stopValidating |
Stop validating session |
POST |
/addBlock |
Submit a validated block (network propagation) |
| Method | Endpoint | Description |
|---|---|---|
GET |
/getGenesisBlock |
Download the Genesis Block data |
POST |
/heartbeat |
Full Node heartbeat registration (discovery) |
GET |
/getFullNodes |
Get the list of active Full Nodes |
GET |
/getPolicy |
Get protocol/version policy |
GET |
/getChain |
Get the blockchain data |
On the first successful Light Node connect (POST /handshake from a LIGHT client), the Full Node appends a VALIDATOR_ONBOARDING block to the chain and records two onboarding transactions:
- 1 KNT to the Full Node reward receiver (
KOKONUT_FULLNODE_REWARD_RECEIVER) - 1 KNT to the validator address
These payouts are funded by the treasury (KOKONUT_TREASURY_ADDRESS).
Persistence: This onboarding event is stored in kovault.db (SQLite). If you keep kovault.db via Docker volume mounts, the 1-time rule survives container rebuilds.
To become an active validator, you must lock at least the network minimum stake (currently 1 KNT) to the stakeVault address.
- Full Nodes expose
POST /stakeLock, which appends aSTAKE_LOCKblock containing an on-chain transfer from your validator address to the stakeVault. - Light Node "Start Staking" will automatically call
POST /stakeLock(if needed) before starting validation. - Stop Staking: When you stop validation, a
POST /stopValidatingcall creates anUNSTAKEblock that returns your deposit from stakeVault to your validator address.
Chain Integrity: All blocks maintain strict timestamp consistency between blocks and their embedded transactions, ensuring hash validation integrity across the network.
Note: In the current model, validator stake and rewards are derived from the blockchain history (the chain is the source of truth).
- Language: Kotlin 2.1.0
- Server Framework: Ktor 3.0.2 (Netty Engine)
- UI Framework: Compose Multiplatform 1.7.1 (Desktop)
- Serialization: Kotlinx Serialization (JSON)
- Database: SQLite 3.47.1.0 (via JDBC)
- Logging: Logback 1.5.12
- Build Tool: Gradle Kotlin DSL
- Fork this repository.
- Create a new branch (
git checkout -b feature/amazing-feature). - Commit your changes (
git commit -m 'Add some amazing feature'). - Push to the branch (
git push origin feature/amazing-feature). - Open a Pull Request.
- Core entities: Add to
core/package - Utilities and API: Add to
util/package - State management: Add to
state/package - Follow Kotlin conventions and maintain backward compatibility
- Write tests for new features
- Timestamp Consistency: When creating transactions within blocks, always use the block's timestamp to ensure hash integrity
- Kotlin: Upgraded to 2.1.0 from 1.9.22
- Ktor: Upgraded to 3.0.2 from 2.3.4 with API compatibility fixes
- Compose Desktop: Upgraded to 1.7.1 from 1.6.0
- SQLite JDBC: Updated to 3.47.1.0
- Logback: Updated to 1.5.12
- Enhanced Chain Integrity: Implemented strict
previousHashvalidation and exact index verification in block addition - Timestamp Consistency Fix: All transactions now use their containing block's timestamp, ensuring hash recalculation consistency
- Improved Validation Logging: Enhanced error reporting shows specific invalid blocks with hash comparisons
- Stop Staking Workflow: Properly calls
/stopValidatingAPI, syncs chain, and updates balance - Post-Validation Updates: Chain sync and balance updates after successful block validation
- Transaction Logging: Accurate recording of all reward transactions
- βοΈ Deterministic Consensus: Validator selection is now fully deterministic.
- Resolves network forks by ensuring all nodes select the exact same validator for every block height using a consensus seed (
previousHash + index). - Eliminates "lucky" or "loud" block production; only the legitimately selected validator's block is accepted.
- Resolves network forks by ensuring all nodes select the exact same validator for every block height using a consensus seed (
- π‘οΈ Fuel Node Slashing Authority:
- Implemented a Fuel Node-exclusive Slashing mechanism.
- Only the Fuel Node ("Judiciary") has the authority to issue
SLASHtransactions to penalize malicious validators. - Protects the network integrity by centralizing the "punishment" power to the bootstrap node.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Official Docker images are available on Docker Hub.
- Fuel Node:
volta2030/knt_fuelnode - Full Node:
volta2030/knt_fullnode
To ensure data persistence (blockchain data, keys), you must mount a volume to /data.
These images set KOKONUT_DATA_DIR=/data, so kovault.db will be created under the mounted /data directory.
The Fuel Node acts as the network bootstrapper.
# -p 80:80 : Bind container port 80 to host port 80
# -v ./data:/data : Persist blockchain data to host's ./data directory
docker run -d \
--name knt_fuelnode \
-p 80:80 \
-v $(pwd)/data_fuel:/data \
volta2030/knt_fuelnodeFull Nodes connect to the network. You can specify a peer to connect to using KOKONUT_PEER.
# -e KOKONUT_PEER : Address of a known node (e.g., Fuel Node or another Full Node)
# -v ./data_full:/data : Use a separate data directory for the Full Node
docker run -d \
--name knt_fullnode \
-p 8080:80 \
-e KOKONUT_PEER="http://<FUEL_NODE_IP>:80" \
-v $(pwd)/data_full:/data \
volta2030/knt_fullnodeCritical Note: Full Nodes MUST configure
KOKONUT_PEERto join an existing network. IfKOKONUT_PEERis omitted or the target peer is unreachable, the Full Node will fail to start (throw an exception). This mechanism prevents accidental network splitting (Split Brain). Only the Fuel Node is allowed to start without a peer to generate the Genesis Block.Note: Replace
<FUEL_NODE_IP>with the actual IP address or domain of your Fuel Node. If running on the same machine, use the host's local network IP.