fullstack-blockchain-app: cryptochain: The blockchain where your balance is a calculation
Inside `zubair-trabzada/fullstack-blockchain-app`, a clean-room Node and React implementation that rebuilds money, mining, and node sync from first principles.
- This repo teaches blockchain by making wallet balance a reconstruction from transaction history, not a stored field.
- Its mining loop is interesting because difficulty adapts to block timing, so proof of work behaves like a control system, not just a hash puzzle.
- Network sync is treated as validation, where nodes accept new state only when the chain rules still hold.
- The project is stronger as a teaching artifact than as a framework starter because it removes abstraction instead of hiding it.
Most blockchain tutorials start with the wrong object. They show you a balance and ask you to trust it. cryptochain does the opposite. It makes the wallet prove its balance by walking the chain, which is the right mental model for understanding why blockchains are auditable, brittle, and useful.
Money is not stored. It is inferred.
The sharpest idea in zubair-trabzada/fullstack-blockchain-app lives in the wallet. A balance is not read from a row in a database. It is reconstructed by scanning blockchain history, finding the last time the wallet spent funds, then adding every relevant output that arrived after that point.
calculateBalance({ chain, address }) {
let hasConductedTransaction = false;
let balance = INITIAL_BALANCE;
for (let i = chain.length - 1; i > 0; i--) {
for (const blockTransaction of chain[i].data) {
if (blockTransaction.input.address === address) {
hasConductedTransaction = true;
balance = blockTransaction.outputMap[address];
}
if (blockTransaction.outputMap[address]) {
balance += blockTransaction.outputMap[address];
}
}
if (hasConductedTransaction) break;
}
return balance;
}
That is a clever compromise. The code does not re-sum every transaction from genesis on each render, but it still preserves the core truth that value comes from history. It is a UTXO-adjacent idea without the ceremony, which makes it perfect for teaching.
The goal is to provide a clear, hands-on example that bridges the gap between frontend and blockchain development.
Proof of work that breathes
The mining loop is more interesting than the usual cartoon version. In Block.mineBlock, the code keeps hashing until the binary form of the hash begins with enough leading zeroes. Then adjustDifficulty nudges the target up or down so block times stay near the configured rate.
mineBlock({ lastBlock, data }) {
let hash, timestamp;
let nonce = 0;
let difficulty = lastBlock.difficulty;
do {
nonce++;
timestamp = Date.now();
difficulty = Block.adjustDifficulty({ originalBlock: lastBlock, timestamp });
hash = cryptoHash(timestamp, lastBlock.hash, data, nonce, difficulty);
} while (
hexToBinary(hash).substring(0, difficulty) !== '0'.repeat(difficulty)
);
return new this({
timestamp,
lastHash: lastBlock.hash,
hash,
data,
difficulty,
nonce
});
}
That binary check matters. Hex gives you coarse jumps. Binary gives you the finer control you need when the chain has to respond to timing instead of pretending every block arrives on schedule.
A node is just a synchronized opinion
Once a block is mined, the node broadcasts it through pub/sub. Other nodes receive the update, validate the chain, and replace local state only if the new chain is longer and still valid. New peers can also bootstrap from a root node, which is a pragmatic shortcut, not a claim of perfect decentralization.
pubsub.subscribe(({ blockchain }) => {
blockchain.replaceChain(receivedChain, true, () => {
transactionPool.clearBlockchainTransactions(receivedChain);
});
});
async function syncWithRootState() {
const chain = await fetch(`${ROOT_NODE_ADDRESS}/api/blocks`).then(r => r.json());
const transactionPool = await fetch(`${ROOT_NODE_ADDRESS}/api/transaction-pool`).then(r => r.json());
// hydrate local node state from the root node
}
| Question | cryptochain | Framework starters |
|---|---|---|
| What holds your money? | A balance computed from chain history. | A state value that is usually hidden behind app plumbing. |
| What is the hard part? | Making validation explicit and readable. | Hiding protocol details behind tooling and conventions. |
| How does mining behave? | Difficulty adapts to block timing. | Mining is often abstracted away or mocked. |
| Who gets the most value? | Readers learning how a blockchain works. | Teams that want to prototype faster with less friction. |
That is why this repo teaches better than a heavier starter kit. Frameworks are great at removing friction. This project is great at removing illusions. When you can see the chain, the wallet, the miner, and the network as separate, testable ideas, the protocol stops feeling mystical.
Why this repo teaches better than a framework starter
The alternatives in the ecosystem are stronger on breadth. Scaffold-ETH gives you a larger surface area, create-eth-app gives you a quick scaffold, and Hardhat gives you the expected development loop. zubair-trabzada/fullstack-blockchain-app is narrower than all of them, but that narrowness is the point. It keeps the protocol visible.
The goal is to provide a clear, hands-on example that bridges the gap between frontend and blockchain development.
There is a cost. The project leans on a root node for bootstrap, it does not attempt full peer discovery, and it feels like what it is, a disciplined prototype. That is a feature in an explainer repo. You learn more from a small machine with the covers off than from a polished machine that refuses to show you its gears.