Machine Coding Problem

Basic Blockchain

maco60macoAllinfrastructurehashingchain-validation
Commonly Asked By:CoinbaseBinanceRipple

Requirements & System Scope

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.

Class Diagram & Entity Relationships

Structural blueprint showcasing block linking and transaction storage:

Loading...
  • Genesis block: Formulates the zero-index root of the trust hierarchy with a custom hardcoded previous hash.
  • Previous Hash Pointer: Binds block sequence; any single bit modification invalidates all forward linkages.

Design Patterns & SOLID Principles

  • Chain of Responsibility Pattern: Inherent in the chain linking model, where blocks validate themselves and delegate forward context checks.
  • Strategy Pattern: Encapsulating difficulty target computation allowing smooth transitions of PoW difficulty values dynamically.
  • Single Responsibility Principle (SRP): Decoupled transactional models (\`Transaction\`) from storage and computation structures (\`Block\`).

Core Execution Workflows

Block Verification and Consensus

  1. Transactions are broadcasted to the memory pool.
  2. A miner packages transactions into a candidate block.
  3. The \`MiningService\` runs the computational PoW loop, incrementing \`nonce\` until the block hash starts with N zeros.
  4. The mined block is added to the local blockchain instance.
  5. Upon receiving an alternate chain fork, the \`resolveFork()\` workflow evaluates length and validates cryptographic integrity before executing a hot-swap.

Concurrency & Thread Safety Strategy

Designing thread-safe data layers during computationally intensive mining tasks:

  • Synchronized Access Control: Thread synchronization or mutex locks prevent race conditions on block additions and fork evaluations.
  • Deep Cloning Chains: Returns defensive copies of block arrays to prevent external mutability bugs during continuous verification checks.

Complete Clean Code Blueprint

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)");
    }
}

๐Ÿ’ฌReview

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...