A Java-based system that combines a custom FTP server-client architecture with a blockchain backend to record, verify, and query transactions. Clients connect to the server over TCP sockets, submit transaction data, and the server batches them into blocks — each secured with SHA-256 hashing, Merkle tree verification, and adaptive mining difficulty.
Clients submit transactions through a custom text-based protocol. The server queues them, and once 4 transactions accumulate, the blockchain mines a new block. The server then broadcasts the block info (transaction IDs, timestamps, height) back to all connected clients and persists records to MySQL.
- Architecture Overview
- Core Components
- How It Works
- Getting Started
- Features
- Project Structure
- Tech Stack
- Work In Progress
- Contributing
- Maintainers
sequenceDiagram
autonumber
participant GUI as GUI (SimpleGUI)
participant C as FTPClient
participant CCH as ClientCommandHandler
participant S as FTPServer
participant CH as ClientHandler
Note over GUI,CH: Connection setup
GUI->>C: new FTPClient(username)
C->>C: Create Socket(127.0.0.1:9090)
C->>S: TCP connect
S->>S: ServerSocket.accept()
S->>CH: new ClientHandler(socket)
S->>S: pool.submit(clientHandler)
Note over C,CH: Handshake
C->>CCH: commandExecution(type=000, user, user)
CCH->>S: [000] from Alice to Server : Alice
CH->>CH: connectConfirm() — parse username
CH-->>CCH: [333] from Server to Alice : connection succeeded
CCH->>C: connectSuccess()
C->>C: Enter polling loop (check upload/query)
Note over S,CH: Server background threads already running
S->>S: processTransactionQueue()
S->>S: processReturnBlock()
S->>S: processBlockInfo()
S->>S: detectTransaction()
S->>S: Chain.queueSizeChecking()
sequenceDiagram
autonumber
participant C as FTPClient
participant S as FTPServer
participant CH as ClientHandler
participant TQ as Transaction Queue
participant BC as Chain (Blockchain)
participant BK as BlockImpl
participant MT as MerkleTree
participant DH as DifficultyHandler
participant DB as MySQL (DatabaseOperator)
Note over C,DB: Client submits a transaction
C->>S: [111] from Alice to Server : <transaction_text>
CH->>CH: upload() — store transaction, wait on lock
S->>S: detectTransaction() finds hasTransaction=true
CH->>CH: handleTransaction() — mark as handling
S->>TQ: transactionInLine.add(transaction)
S->>S: clientsInLine.add("Alice")
Note over TQ,BC: Queue drains into blockchain (needs 4 txns)
TQ->>BC: addTransaction(tx1)
Note right of TQ: ...repeat for tx2, tx3, tx4
BC->>BC: queueSizeChecking() detects size ≥ 4
BC->>BC: addBlock() — poll 4 transactions
Note over BK,DH: Mining a new block
BC->>BK: new BlockImpl(headBlock, transactions[4])
BK->>MT: new MerkleTreeImpl(transactions)
MT->>MT: Hash leaves with SHA-256
MT->>MT: Pair and hash up the tree
MT-->>BK: merkleRootHash
BK->>BK: Generate transactionIDs (SHA-256)
BK->>BK: Set initial difficulty from previous block
rect rgb(255, 248, 230)
Note over BK: Proof-of-Work mining loop
BK->>BK: nonce++ → SHA-256(prevHash + merkle + nonce + ...)
BK->>BK: Check leadingZeros > difficulty OR timeout (10 min)
BK-->>BK: currentBlockHash found
end
BK->>DH: adjustDifficulty(blockProcessTime, difficulty)
DH->>DH: Chain of Responsibility: safe or over?
DH-->>BK: New difficulty level
BK-->>BC: New block ready
BC->>BC: headBlock = newBlock (link to chain)
Note over S,DB: Server detects new block and broadcasts
S->>S: processReturnBlock() detects height change
S->>S: blockProcessingQueue.put(head)
S->>S: processBlockInfo() takes block
loop For each of 4 transactions
S->>S: clientsInLine.take() → username
S->>DB: insert(txID, user, time, fee, height)
end
Note over S,C: Broadcast to ALL connected clients
S-->>CH: [333] from server to Alice : txID,user,time,fee,height/.../...
CH->>CH: returnInfo() → finishTransaction()
CH-->>C: Response with new block data
C->>C: GUI displays block info
The blockchain is managed by the Chain class (singleton pattern), backed by a linked list of BlockImpl nodes:
- Genesis Block — Automatically created on chain initialization with random seed data.
- Block Creation — When 4 transactions are queued, a new
BlockImplis constructed, linking to the previous block via its SHA-256 hash. - Block Structure — Each block stores:
previousBlockHash/currentBlockHashmerkleRootHash— root of the block's Merkle treetransactions[]/transactionIDs[]— raw data and their unique SHA-256 identifiersheight,nonce,timestamp,difficulty
- Transaction Query — Given a block height and transaction ID (TXID), the chain traverses to the target block and verifies the transaction exists via the Merkle tree before returning the data.
Each block constructs a MerkleTreeImpl from its transactions:
- Leaf nodes — SHA-256 hash of each transaction.
- Internal nodes — SHA-256 hash of concatenated child pairs. If the count is odd, the last node is duplicated.
- Root — The final hash becomes the block's
merkleRootHash.
The tree supports a search(inputData) method that re-derives the root from the leaf level, checking if the query data's hash path leads to the stored Merkle root — providing O(log n) data integrity verification.
Block mining follows a proof-of-work scheme based on leading-zero requirements in the block hash:
- The miner increments a
nonceuntil the resulting SHA-256 hash has more leading zeros than the current difficulty target. - A 10-minute timeout prevents infinite mining on high difficulty — if exceeded, the block is accepted regardless.
- Adaptive difficulty is handled by
DifficultyHandlerusing a Chain of Responsibility pattern:timeIntervalSafe— Maps block creation time (0–600 seconds) to difficulty levels 0–5.timeIntervalOver— If mining exceeds the max threshold, a random lower difficulty is assigned to prevent stalling.
| Block Time (s) | Difficulty (leading zeros) |
|---|---|
| 0 | 0 |
| ≤ 120 | 1 |
| ≤ 240 | 2 |
| ≤ 360 | 3 |
| ≤ 480 | 4 |
| ≤ 600 | 5 |
| > 600 | Random (0–4) |
FTPServer (port 9090):
- Accepts multiple client connections via a thread pool (
ExecutorService). - Each client is managed by a dedicated
ClientHandlerthread. - Maintains three concurrent queues:
transactionInLine,clientsInLine, andblockProcessingQueue. - Background threads handle: transaction detection → queue processing → chain submission → new block detection → broadcast to all clients.
- Persists transaction metadata (ID, user, timestamp, handling fee, block height) to MySQL via
DatabaseOperator+ HikariCP connection pooling.
FTPClient:
- Connects to the server, authenticates with a username, then polls for upload/query requests from the GUI.
- Uses
ClientCommandHandlerfor synchronized send-then-receive communication. - Displays results (new block info or query results) through the GUI layer.
All communication uses a structured text format:
[TYPE] from SENDER to RECEIVER : PAYLOAD
| Code | Type | Description |
|---|---|---|
000 |
CONNECT | Client connection handshake |
111 |
UPLOAD | Transaction submission |
222 |
QUERY | Transaction lookup by TXID |
333 |
SUCCESS | Server acknowledgment |
444 |
ERROR | Error response |
Upload responses contain multiple transaction records separated by /, with individual fields separated by ,.
See the Sequence Diagrams above for detailed step-by-step flows. In summary:
- Client connects → sends
[000] from Alice to Server : Alice→ server responds with[333]success. - Client uploads a transaction → sends
[111] from Alice to Server : <transaction_text>. - Server queues the transaction. Once 4 transactions accumulate, the blockchain mines a new block.
- Mining —
BlockImplconstructs a Merkle tree, then searches for a nonce producing a SHA-256 hash meeting the current difficulty. Difficulty adjusts based on how long mining took. - Broadcast — Server sends the new block info (transaction IDs, users, timestamps, heights) to all connected clients.
- Persistence — Transaction metadata is inserted into MySQL for future queries.
- Client queries → sends
[222] from Alice to Server : <TXID>→ server looks up the record in the database and returns the details.
- Java 17+
- Gradle 7.5+ — Install guide
- MySQL — A running MySQL instance (for transaction persistence)
gradle clean buildStart the server first, then launch one or more clients:
# Terminal 1 — Start the server
gradle runServer
# Terminal 2+ — Start clients
gradle runClientThe server listens on 127.0.0.1:9090 by default.
- Blockchain with Proof-of-Work — SHA-256 mining with nonce search and leading-zero difficulty.
- Merkle Tree Verification — Every block builds a Merkle tree for tamper-evident transaction integrity.
- Adaptive Difficulty — Automatically adjusts mining difficulty based on block creation time using a Chain of Responsibility pattern.
- Multi-Client Support — Thread-pooled server handles concurrent client connections and transactions.
- Real-Time Broadcast — All connected clients are notified when a new block is mined.
- Transaction Query — Look up any transaction by its ID; verified against the Merkle tree before returning.
- Custom FTP Protocol — Structured text-based protocol for upload, query, and response handling.
- Database Persistence — Transaction records stored in MySQL via HikariCP connection pooling.
- GUI Interface — Simple GUI for submitting transactions and viewing results.
src/main/java/project/block_chain/
├── BlockChain/
│ ├── Block.java # Block interface
│ ├── BlockImpl.java # Block implementation (genesis, mining, hashing)
│ ├── BlockChain.java # Blockchain interface
│ ├── Chain.java # Singleton blockchain manager
│ ├── MerkleTree.java # Merkle tree interface
│ ├── MerkleTreeImpl.java # Merkle tree build & search
│ ├── DifficultyHandler.java # Adaptive difficulty (Chain of Responsibility)
│ ├── SHA256.java # SHA-256 hashing utilities
│ ├── BackupService.java # Backup interface
│ ├── BlockchainBackupHandler.java # Serialization-based block backup
│ └── SHA256SignatureHandler.java # RSA digital signature for backups
├── FTP/
│ ├── FTPServer.java # Multi-threaded server with queue management
│ ├── FTPClient.java # Client with GUI integration
│ ├── ClientHandler.java # Per-client server-side handler
│ ├── ClientCommandHandler.java # Client-side command send/receive
│ ├── CommandFormat.java # Protocol message formatting & parsing
│ ├── CommandMap.java # Command type code mapping
│ └── DatabaseOperator.java # MySQL operations (insert/query)
├── GUI/
│ ├── GUI.java # GUI interface
│ └── SimpleGUI.java # Simple GUI implementation
└── Main/
├── ServerMain.java # Server entry point
└── ClientMain.java # Client entry point
| Component | Technology |
|---|---|
| Language | Java 17 |
| Build | Gradle 7.5.1 / Maven |
| Database | MySQL 8.0 (mysql-connector-java) |
| Connection Pool | HikariCP 5.0.1 |
| Serialization | Jackson XML 2.13 |
| Logging | SLF4J 1.7 + Logback 1.2 |
| Cryptography | SHA-256 (java.security), RSA (backup signing) |
- Blockchain Backup & Restore — Block serialization with RSA digital signature verification. Backup files are signed with a private key; restoration verifies integrity using the corresponding public key. (Partially implemented)
- Database Layer Completion — Full CRUD operations and advanced query support.
- Timeout-Based Block Creation — Optional mode to create blocks even when fewer than 4 transactions are queued, after a configurable timeout.
- Blockchain Rebuild — Restore a full chain from backup files given a public key and previous chain length.
Feel free to dive in! Open an issue or submit a PR.
| kji | vanillaSky |
- Satoshi Nakamoto, Bitcoin: A Peer-to-Peer Electronic Cash System, 2008.