Thuta Learning
ProjectsSecurityadvanced

Mini Blockchain Project — Part 3: Finishing Up with Wallets, Signatures & Chain Validation

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Apply Mini Blockchain Project — Part 3: Finishing Up with Wallets, Signatures & Chain Validation in a hands-on project
  • Write and run your own code
  • Build a complete project step by step

Let's think about this for a second

In this final part, we'll actually wire up the public/private key concepts you learned in the wallets, keys, and wallet-safety chapters. A real wallet signs a transaction with a private key, and everyone else can verify it with the public key (wallet address). We'll also prove out immutability, blockchain's core security property, by writing an isChainValid() function — it recalculates each block's hash and checks it against the original hash, and checks whether the previousHash link is correct. We'll wrap up the whole project by manually tampering with data in the chain and testing whether the validation function catches it.

Let's build it

Generate a wallet keyPair with crypto.generateKeyPairSync('ec', {namedCurve:'secp256k1'}). Add three methods to the Transaction class — calculateHash(), sign(signingKey), and isValid() — where sign() signs the transaction hash with the private key and stores it in the signature field, and isValid() verifies the signature against the public key. In the Blockchain class, write an isChainValid() method — using a for loop, recalculate chain[i].hash with calculateHash() and compare it, and check whether chain[i].previousHash === chain[i-1].hash. Finally, console.log(myChain.isChainValid()) should print true; then manually change chain[1].data and call isChainValid() again — it should now return false.

Code Example

javascript
const crypto = require('crypto');
const { generateKeyPairSync, sign, verify } = crypto;

// 1. Wallet key pair
const { publicKey, privateKey } = generateKeyPairSync('ec', {
  namedCurve: 'secp256k1',
  publicKeyEncoding: { type: 'spki', format: 'pem' },
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
});

class Transaction {
  constructor(fromAddress, toAddress, amount) {
    this.fromAddress = fromAddress;
    this.toAddress = toAddress;
    this.amount = amount;
  }

  calculateHash() {
    return crypto
      .createHash('sha256')
      .update(this.fromAddress + this.toAddress + this.amount)
      .digest('hex');
  }

  sign(signingKeyPem) {
    this.signature = sign('sha256', Buffer.from(this.calculateHash()), signingKeyPem).toString('hex');
  }

  isValid(publicKeyPem) {
    if (!this.signature) return false;
    return verify('sha256', Buffer.from(this.calculateHash()), publicKeyPem, Buffer.from(this.signature, 'hex'));
  }
}

class Blockchain {
  // ... chain, difficulty, mineBlock လို part 2 ကလာတဲ့ property/method တွေ ဆက်သုံးပါ
  isChainValid() {
    for (let i = 1; i < this.chain.length; i++) {
      const current = this.chain[i];
      const previous = this.chain[i - 1];

      if (current.hash !== current.calculateHash()) return false;
      if (current.previousHash !== previous.hash) return false;
    }
    return true;
  }
}

const tx = new Transaction('wallet-A', 'wallet-B', 25);
tx.sign(privateKey);
console.log('Transaction valid?', tx.isValid(publicKey));

// tamper test (myChain က Part 1-2 ကနေ ဆက်ခံထားတဲ့ instance)
console.log('Blockchain valid?', myChain.isChainValid());
myChain.chain[1].data = { amount: 999999 };
console.log('Blockchain valid after tamper?', myChain.isChainValid());
You should see
Before tampering, isChainValid() prints true. After manually editing chain[1].data and calling it again, it prints false — proof that the blockchain's tamper detection is working.

5-Minute Try-It

Generate two wallet key pairs, sign a transaction from wallet A to wallet B and send it, then spend 5 minutes checking whether isValid() returns true.

A Quick Word of Caution

Never print a private key with console.log(), commit it to a GitHub repo, or anything like that in a real project — this demo generates a throwaway key purely for local learning.

Easy traps

  • Forgetting to check the signingKey's public key against fromAddress when signing a Transaction, which leaves the door open for a wallet to sign with the wrong private key
  • During the tamper test, changing the data but then also manually rewriting the block.hash field, which makes isChainValid() falsely return true (to properly test tamper detection, only change the data and leave the hash field untouched)

Now Try It Yourself

Generate two wallet key pairs, sign a transaction from wallet A to wallet B and send it, then spend 5 minutes checking whether isValid() returns true.

You'll know it worked when: Before tampering, isChainValid() prints true. After manually editing chain[1].data and calling it again, it prints false — proof that the blockchain's tamper detection is working.

Mini Blockchain Project — Part 3: Finishing Up with Wallets, Signatures & Chain Validation | Thuta Learning