Functional Scope (In-Scope)
- Immutability Chain Linking: Each block stores the preceding block's cryptographic hash, forming an append-only verifiable chain.
- Proof-of-Work (PoW) Mining: Increments nonces repeatedly to resolve complex hashing constraints matching the target difficulty.
- Digital Signatures & Transactions: Cryptographically signs transactions to support ownership validation.
- Fork Resolution (Nakamoto Consensus): Resolves discrepancies by evaluating competitive chains and selecting the longest valid chain.
Explicit Boundaries (Out-of-Scope)
- Peer-to-Peer Networking: Omits full gossiping network transport protocols (gRPC, TCP sockets).
- Advanced Smart Contracts: Excludes executing EVM bytecode or transaction-based decentralized state machines.
Clean reference designs demonstrating basic proof-of-work blockchain in Java and Python:
// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class Transaction {
private final String sender;
private final String recipient;
private final double amount;
private final String signature;
private final long timestamp;
public Transaction(String sender, String recipient, double amount, String signature) {
this.sender = sender;
this.recipient = recipient;
this.amount = amount;
this.signature = signature;
this.timestamp = System.currentTimeMillis();
}
public String getSender() { return sender; }
public String getRecipient() { return recipient; }
public double getAmount() { return amount; }
public String getSignature() { return signature; }
public long getTimestamp() { return timestamp; }
public String hashValue() {
try {
String data = sender + ":" + recipient + ":" + amount + ":" + signature + ":" + timestamp;
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = digest.digest(data.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : hashBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public boolean verifySignature() {
// Simplified cryptographic verification simulation
if (sender.equals("GENESIS")) return true;
return signature != null && !signature.isEmpty() && signature.startsWith("sig_");
}
@Override
public String toString() {
return sender + "->" + recipient + ":" + amount + "[" + signature + "]";
}
}
class Block {
private final int index;
private final long timestamp;
private final List<Transaction> transactions;
private final String previousHash;
private String hash;
private int nonce;
public Block(int index, List<Transaction> transactions, String previousHash) {
this.index = index;
this.timestamp = System.currentTimeMillis();
this.transactions = new ArrayList<>(transactions);
this.previousHash = previousHash;
this.nonce = 0;
this.hash = calculateHash();
}
public Block(int index, long timestamp, List<Transaction> transactions, String previousHash, int nonce, String hash) {
this.index = index;
this.timestamp = timestamp;
this.transactions = new ArrayList<>(transactions);
this.previousHash = previousHash;
this.nonce = nonce;
this.hash = hash;
}
public String calculateHash() {
try {
StringBuilder txData = new StringBuilder();
for (Transaction tx : transactions) {
txData.append(tx.hashValue());
}
String data = index + ":" + timestamp + ":" + txData.toString() + ":" + previousHash + ":" + nonce;
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = digest.digest(data.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : hashBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-256 algorithm not found", e);
}
}
public void mineBlock(int difficulty) {
String target = new String(new char[difficulty]).replace('\0', '0');
while (!hash.substring(0, difficulty).equals(target)) {
nonce++;
hash = calculateHash();
}
}
public int getIndex() { return index; }
public long getTimestamp() { return timestamp; }
public List<Transaction> getTransactions() { return new ArrayList<>(transactions); }
public String getPreviousHash() { return previousHash; }
public String getHash() { return hash; }
public int getNonce() { return nonce; }
// For deliberate tampering testing
public void tamperTransaction(int index, Transaction tamperedTx) {
this.transactions.set(index, tamperedTx);
}
}
class Blockchain {
private List<Block> chain;
private final int difficulty;
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
public Blockchain(int difficulty) {
this.chain = new ArrayList<>();
this.difficulty = difficulty;
// Genesis block
Block genesis = new Block(0, new ArrayList<>(), "0");
genesis.mineBlock(difficulty);
chain.add(genesis);
}
public Block getLatestBlock() {
rwLock.readLock().lock();
try {
return chain.get(chain.size() - 1);
} finally {
rwLock.readLock().unlock();
}
}
public void addBlock(Block newBlock) {
rwLock.writeLock().lock();
try {
newBlock.mineBlock(difficulty);
chain.add(newBlock);
} finally {
rwLock.writeLock().unlock();
}
}
public boolean isChainValid() {
rwLock.readLock().lock();
try {
return isValidChain(this.chain, this.difficulty);
} finally {
rwLock.readLock().unlock();
}
}
public static boolean isValidChain(List<Block> chainToValidate, int difficulty) {
String target = new String(new char[difficulty]).replace('\0', '0');
for (int i = 1; i < chainToValidate.size(); i++) {
Block currentBlock = chainToValidate.get(i);
Block previousBlock = chainToValidate.get(i - 1);
// 1. Verify self-hash integrity
if (!currentBlock.getHash().equals(currentBlock.calculateHash())) {
System.out.println("[VALIDATION FAILURE] Block " + currentBlock.getIndex() + " hash has been modified.");
return false;
}
// 2. Verify chain linkage
if (!currentBlock.getPreviousHash().equals(previousBlock.getHash())) {
System.out.println("[VALIDATION FAILURE] Block " + currentBlock.getIndex() + " previous hash mismatch.");
return false;
}
// 3. Verify Proof-of-Work difficulty prefix
if (!currentBlock.getHash().substring(0, difficulty).equals(target)) {
System.out.println("[VALIDATION FAILURE] Block " + currentBlock.getIndex() + " does not meet Proof of Work target.");
return false;
}
// 4. Verify transactions inside the block
for (Transaction tx : currentBlock.getTransactions()) {
if (!tx.verifySignature()) {
System.out.println("[VALIDATION FAILURE] Invalid transaction signature detected in Block " + currentBlock.getIndex());
return false;
}
}
}
return true;
}
public boolean resolveFork(List<Block> newChain) {
rwLock.writeLock().lock();
try {
if (newChain.size() > this.chain.size() && isValidChain(newChain, this.difficulty)) {
System.out.println("[CONSENSUS] Fork resolved! Accepted longer chain of length " + newChain.size());
this.chain = new ArrayList<>(newChain);
return true;
}
System.out.println("[CONSENSUS] Rejected incoming fork. Local chain is equal/longer or invalid.");
return false;
} finally {
rwLock.writeLock().unlock();
}
}
public List<Block> getChain() {
rwLock.readLock().lock();
try {
return new ArrayList<>(chain);
} finally {
rwLock.readLock().unlock();
}
}
}
public class Main {
public static void main(String[] args) {
System.out.println("=== INITIALIZING BLOCKCHAIN SIMULATOR (DIFFICULTY = 2) ===");
Blockchain mainChain = new Blockchain(2);
System.out.println("\n=== 1. MINING INITIAL TRANSACTIONS ===");
List<Transaction> block1Tx = Arrays.asList(
new Transaction("Alice", "Bob", 50.0, "sig_alice_123"),
new Transaction("Bob", "Charlie", 25.0, "sig_bob_456")
);
Block block1 = new Block(1, block1Tx, mainChain.getLatestBlock().getHash());
mainChain.addBlock(block1);
System.out.println("Mined Block 1: " + block1.getHash());
List<Transaction> block2Tx = Arrays.asList(
new Transaction("Charlie", "David", 10.0, "sig_charlie_789")
);
Block block2 = new Block(2, block2Tx, mainChain.getLatestBlock().getHash());
mainChain.addBlock(block2);
System.out.println("Mined Block 2: " + block2.getHash());
System.out.println("Blockchain length: " + mainChain.getChain().size() + " | Is Valid: " + mainChain.isChainValid());
System.out.println("\n=== 2. SIMULATING A LONGER VALID FORK (Nakamoto Consensus) ===");
// Duplicate the chain state up to block 1 to simulate a fork starting from block 1
List<Block> forkChain = new ArrayList<>();
forkChain.add(mainChain.getChain().get(0));
forkChain.add(mainChain.getChain().get(1));
// Create alternative Block 2 and 3 on the fork chain
List<Transaction> forkBlock2Tx = Arrays.asList(
new Transaction("Bob", "Eve", 40.0, "sig_bob_eve_fork")
);
Block forkBlock2 = new Block(2, forkBlock2Tx, forkChain.get(forkChain.size() - 1).getHash());
forkBlock2.mineBlock(2);
forkChain.add(forkBlock2);
List<Transaction> forkBlock3Tx = Arrays.asList(
new Transaction("Eve", "Alice", 15.0, "sig_eve_alice_fork")
);
Block forkBlock3 = new Block(3, forkBlock3Tx, forkChain.get(forkChain.size() - 1).getHash());
forkBlock3.mineBlock(2);
forkChain.add(forkBlock3);
System.out.println("Attempting fork resolution with fork chain length " + forkChain.size());
boolean resolved = mainChain.resolveFork(forkChain);
System.out.println("Fork resolution status: " + resolved);
System.out.println("New main blockchain length: " + mainChain.getChain().size());
System.out.println("\n=== 3. TAMPER DETECTION SYSTEM ===");
System.out.println("Deliberately tampering block 1 with illegal transaction...");
Block hackedBlock = mainChain.getChain().get(1);
Transaction hackedTx = new Transaction("Alice", "Hacker", 9999.0, "sig_alice_stolen");
hackedBlock.tamperTransaction(0, hackedTx);
System.out.println("Checking blockchain validity after tampering...");
boolean isValid = mainChain.isChainValid();
System.out.println("Validity Status: " + isValid + " (Expected: false)");
}
}