The blockchain bootcamp · Chapter 1 of 18 · Blockchain · new chapter every Saturday evening
By the end of this chapter: Define block, chain, hash, nonce, consensus and finality accurately enough to read anything else.
The problem
Emma is a front‑end engineer who has just been handed a ticket to add a “view latest block” widget to the company’s dashboard. The design mock shows the block number, its hash, the timestamp, and a badge that says “finalised”. Emma has never written blockchain‑related code, but she has a working React codebase and a CI pipeline that already ships daily.
She opens the Ethereum documentation, reads the “block” page, and copies a snippet that calls provider.getBlockNumber(). The widget shows a number, but the hash field is empty, the timestamp looks like a Unix epoch, and the “finalised” badge never appears. When she asks the senior dev for clarification, the answer is “finality means the block is immutable – just trust the node”. Emma’s PR sits idle for a day, the sprint loses a story point, and the product manager asks why the feature is delayed.
Emma’s blockers are:
- She cannot distinguish the meaning of “block”, “chain”, “hash”, “nonce”, “consensus”, and “finality”, so she cannot map the API fields to the concepts the UI must display.
- Without a concrete mental model, she cannot decide which node endpoint to trust for “finalised” status.
- The delay costs the team a day of development and a missed demo to stakeholders.
The chapter will give Emma (and anyone like her) a precise, production‑ready understanding of those six terms, plus a tiny script she can run to verify each concept against a live mainnet node.
Before you start
-
Node.js 20.9.0 (or later) –
node -vshould outputv20.x.x. -
npm 10.2.3 –
npm -vshould output10.x.x. -
ethers 6.7.0 – install with
npm i ethers@6.7.0. - Access to a public Ethereum JSON‑RPC endpoint (e.g. Infura, Alchemy, or the free Cloudflare endpoint
https://cloudflare-eth.com). No API key is required for the Cloudflare endpoint. - A terminal that can run
node.
Verify the setup by creating a file check.js with:
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://cloudflare-eth.com");
provider.getBlockNumber().then(num => console.log(`Latest block: ${num}`));
Run node check.js. You should see something like:
Latest block: 19784234
If that works, you are ready to continue.
What does a block really contain?
A block is a bundle of transactions plus a small header that links it to the rest of the chain. The header fields that matter for our vocabulary are:
| Field | Meaning |
|---|---|
parentHash |
SHA‑256 hash of the previous block’s header – the cryptographic link. |
number |
Sequential block height, starting at 0 for the genesis block. |
timestamp |
Unix epoch seconds when the block was proposed by a validator/miner. |
nonce |
64‑bit value that miners adjust to satisfy the consensus difficulty (PoW) or a placeholder in PoS. |
hash |
Keccak‑256 hash of the entire block header, used as the block’s identifier. |
stateRoot |
Root of the Merkle‑Patricia trie representing the global state after this block. |
Why the header matters: the hash of the header is what the next block will reference via parentHash. Changing any field (even a single bit) would produce a completely different hash, breaking the link and alerting the network that tampering occurred.
How does a chain emerge from those blocks?
A chain is simply the ordered list of blocks where each block’s parentHash matches the hash of its predecessor. This creates an immutable sequence because any attempt to rewrite history would require recomputing the hash of the altered block and all subsequent blocks.
In practice, nodes maintain a canonical chain (the longest or highest‑total‑difficulty chain) and discard forks that do not meet the consensus rule set. The chain is therefore a distributed data structure: every node stores the same sequence, but each node arrives at the same ordering independently through the consensus algorithm.
Why is a hash the backbone of trust?
A hash is a deterministic, one‑way function that maps arbitrary data to a fixed‑size output (32 bytes for Keccak‑256). Its crucial properties:
- Collision resistance – finding two different inputs with the same hash is computationally infeasible.
- Pre‑image resistance – given a hash, it is infeasible to reconstruct the original input.
- Avalanche effect – flipping a single bit changes ~50 % of the output bits.
Because a block’s hash uniquely identifies its header, any modification to the block (even a single transaction) changes the hash, which then breaks the parentHash link in the next block. The network can instantly detect the inconsistency, rejecting the tampered block.
What is a nonce and how does it enable Proof‑of‑Work?
In PoW chains (e.g., Ethereum pre‑the Merge), a miner repeatedly changes the nonce field and recomputes the block header hash until the resulting hash is numerically lower than the current target (derived from the difficulty). The target is a 256‑bit number; lower hashes are rarer, making the search computationally costly.
The process:
- Assemble the block header (including the current
nonce). - Compute
hash = keccak256(header). - Compare
hashtotarget. Ifhash < target, the block is valid; otherwise, incrementnonceand repeat.
The nonce is therefore the proof that the miner expended work. In PoS chains (Ethereum post‑Merge), the nonce field is retained for compatibility but is not used for mining; instead, validators sign the block with their private key.
How do consensus and finality differ?
Consensus is the set of rules that all honest nodes follow to agree on the next block. It defines:
- How a block is considered valid (e.g., PoW hash below target, PoS signature verification).
- How conflicts (forks) are resolved (e.g., longest‑chain rule, Casper FFG finality gadget).
Finality is a guarantee that a block, once reached, will never be reverted under normal network conditions. In PoW, finality is probabilistic: the deeper a block is (e.g., 6 confirmations ≈ 1 hour on Ethereum), the lower the chance of reorg. In PoS, finality is cryptographic: after the Casper finality gadget finalises a block, any attempt to revert would require >⅓ of the total stake to be malicious, which is economically infeasible.
Thus:
| Property | PoW (pre‑Merge) | PoS (post‑Merge) |
|---|---|---|
| Consensus mechanism | Mining, difficulty adjustment | Validator voting, slashing |
| Finality | Probabilistic, depends on confirmations | Immediate (once finalised) |
| Typical finality time | 1‑2 hours for 6 confirmations | < 30 seconds after attestation |
Understanding this distinction lets Emma decide whether to display a “finalised” badge only after a block is finalised (PoS) or after a configurable number of confirmations (PoW).
Build it
We will write a tiny Node script that fetches a block, prints every vocabulary term, and indicates whether the block is finalised according to the current consensus (Ethereum mainnet, PoS).
- Create the project folder
mkdir eth-vocab-demo && cd eth-vocab-demo
npm init -y
npm i ethers@6.7.0
Why: isolates the demo and ensures the correct ethers version.
-
Create
blockInfo.js
// blockInfo.js
import { ethers } from "ethers";
// 1️⃣ Choose a reliable public RPC – Cloudflare is free and does not need an API key.
const provider = new ethers.JsonRpcProvider("https://cloudflare-eth.com");
// 2️⃣ Fetch the latest block with full transaction data (needed for stateRoot etc.)
const main = async () => {
const block = await provider.getBlock("latest", true);
if (!block) {
console.error("❌ Could not fetch block");
process.exit(1);
}
// 3️⃣ Print the vocabulary items
console.log("🔗 Block chain link");
console.log(`Block number : ${block.number}`);
console.log(`Parent hash : ${block.parentHash}`);
console.log(`Block hash (ID) : ${block.hash}`);
console.log(`Timestamp (UTC) : ${new Date(block.timestamp * 1000).toISOString()}`);
console.log(`Nonce (hex) : ${block.nonce}`);
console.log(`State root : ${block.stateRoot}`);
// 4️⃣ Determine finality – on Ethereum PoS, a block is finalised when
// `block.finalized` is true in the `eth_getBlockByNumber` response.
// ethers does not expose this directly, so we use a low‑level call.
const raw = await provider.send("eth_getBlockByNumber", [
ethers.toQuantity(block.number),
false,
]);
const isFinalised = raw.finalized === true;
console.log(`🛡️ Finalised? : ${isFinalised ? "yes" : "no"}`);
};
main().catch(err => {
console.error("❌ Unexpected error:", err);
process.exit(1);
});
Why: The script demonstrates each term in context, and the low‑level RPC call shows how finality is exposed.
- Run the script
node blockInfo.js
Expected output (values will differ):
🔗 Block chain link
Block number : 19784234
Parent hash : 0x8c9a5d... (64 hex chars)
Block hash (ID) : 0x5e2f1b... (64 hex chars)
Timestamp (UTC) : 2024-10-17T08:12:45.000Z
Nonce (hex) : 0x0000000000000000
State root : 0xabc123... (64 hex chars)
🛡️ Finalised? : yes
How to confirm: The block.hash field must be a 66‑character hex string (including 0x). The finalised field should be true on mainnet after the Merge; if it is false, the block is still in the canonical chain but not yet finalised.
- Validate the hash linkage
node -e "import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('https://cloudflare-eth.com');
(async () => {
const b = await provider.getBlock('latest');
const parent = await provider.getBlock(b.parentHash);
console.log('Parent hash matches?', parent?.hash === b.parentHash);
})();"
Expected output:
Parent hash matches? true
Why: Confirms that the parentHash of the current block truly points to the hash of its predecessor, cementing the chain concept.
You now have a runnable artifact that demonstrates block, chain, hash, nonce, consensus (via the RPC endpoint), and finality.
When this breaks
| Symptom | Cause | Fix |
|---|---|---|
Error: Error: Invalid JSON RPC response: {"jsonrpc":"2.0","id":1,"result":null}
|
The RPC endpoint is rate‑limited or unavailable. | Switch to another public endpoint (e.g., https://mainnet.infura.io/v3/<PROJECT_ID>) or add a retry wrapper. |
Output: Block hash (ID) : undefined
|
The provider call used getBlock("latest", false) which omits the hash in some older ethers versions. |
Ensure you are using ethers 6.7.0 and call await provider.getBlock("latest", true) (the second argument forces full block data). |
finalised field missing |
Using a PoW‑only node (e.g., a private geth with --dev) that does not implement the post‑Merge finalized flag. |
Connect to a post‑Merge mainnet node (Cloudflare, Infura, Alchemy) that supports the engine_getPayloadV1 API, or omit finality check for PoW chains. |
Nonce shows 0x0 on every block |
On Ethereum PoS the nonce field is always zero; you expected a changing value. |
Remember that PoS does not use the nonce for mining. If you need a PoW example, query a testnet that still runs PoW (e.g., Goerli before its shutdown) or simulate a PoW block locally with geth --dev. |
Parent hash matches? false |
You inadvertently queried a pending block ("pending" tag) whose parent hash may be null. |
Use a confirmed block number (await provider.getBlockNumber()) instead of "pending" or "latest" when checking linkage. |
What it costs
| Technique | Cost / Trade‑off |
|---|---|
Fetching full block data (true flag) |
Increases RPC payload size (~10 KB per block). On rate‑limited endpoints this can hit limits quickly. |
| Reliance on a third‑party RPC | You trust the provider’s view of finality. If the provider is compromised, the finalised flag could be spoofed. For high‑value dApps, run your own archival node. |
| Displaying finality badge immediately (PoS) | Users may see a block marked finalised even if a minor reorg occurs due to network latency; the risk is negligible on Ethereum but higher on newer PoS chains with shorter finality windows. |
| Using PoW nonce logic for teaching | PoW is deprecated on Ethereum; the example may mislead readers about current consensus. Keep the nonce example confined to “historical context”. |
| Running a local node for verification | Requires ~1 TB of disk for full archival sync and several hours of CPU time; overkill for a UI widget but invaluable for auditors. |
In the interview
Interviewer: “Can you explain the difference between consensus and finality in Ethereum, and why a dApp might need both concepts?”
Weak answer: “Consensus is how nodes agree on blocks, and finality means the block can’t be changed. So we just wait for the block to be finalised before we show it.”
Why it’s weak: It repeats definitions without linking them to practical implications. It also ignores the probabilistic nature of finality on PoW and the concrete mechanism (Casper) on PoS.
Strong answer: “Consensus is the rule set that determines which block is valid and how forks are resolved – on Ethereum that’s PoW pre‑Merge and PoS with Casper post‑Merge. Finality is the guarantee that once a block is finalised, the network will not revert it under honest conditions. In PoS, finality is achieved via validator attestations and a slashing‑based finality gadget, giving us immediate finality after a block is checkpointed. In PoW, we rely on confirmations; each additional block reduces the probability of a reorg exponentially. A dApp that displays balances must wait for enough confirmations on PoW to be confident the state won’t roll back, whereas on PoS it can rely on the finalized flag and update UI instantly. The trade‑off is latency versus security – waiting longer reduces risk but hurts UX.”
What a senior candidate adds: they discuss the quantitative risk (e.g., 6 confirmations ≈ 99.9 % certainty on PoW), mention that finality checkpoints are stored in the beacon chain, and note that some layer‑2 solutions inherit finality from the underlying chain, affecting withdrawal windows.
Follow‑up to separate experience from theory: “Tell me about a time you had to decide how many confirmations to wait for before processing a withdrawal, and how you measured the risk.” A candidate who has actually built such a flow will reference real numbers (e.g., 12 confirmations on a PoW testnet, or using the eth_getBlockByNumber finalized flag on mainnet) and discuss monitoring reorg statistics.
Your tasks
Identify block fields
Using the script from Build it, copy the JSON output of a block (runnode -e "import { ethers } from 'ethers'; const p = new ethers.JsonRpcProvider('https://cloudflare-eth.com'); p.getBlock('latest').then(b=>console.log(JSON.stringify(b,null,2)))"). Write down the values fornumber,hash,parentHash,timestamp,nonce, andstateRoot. Verify thatparentHashmatches thehashof the previous block by fetching the predecessor. Done when both hashes match exactly.Compute a block header hash manually
Installkeccak256(npm i keccak256) and write a script that assembles the RLP‑encoded header of a known block (use the fields from task 1) and hashes it with Keccak‑256. Compare the result to thehashfield from the RPC. Done when the two hex strings are identical.Simulate a PoW nonce search (educational only)
Write a Node script that takes a simple string (e.g.,"demo"), appends an integer nonce, hashes it with Keccak‑256, and stops when the hash starts with three leading zeroes (0x000...). Print the nonce and hash. Done when the script finds a nonce within a reasonable time (< 30 seconds on a modern laptop).Explain finality choice
Draft a short (150‑word) design note for a hypothetical dApp that must display a user’s token balance after a transfer. State whether you would rely on thefinalizedflag or a fixed number of confirmations, and justify the decision with numbers (e.g., expected reorg probability, UX latency). Done when the note includes a concrete confirmation count or a reference to thefinalizedflag and explains the trade‑off.Diagnose a mismatch
Modify the script from task 1 to deliberately request a block number that does not exist (e.g.,9999999999). Observe the error, then fix the script so it gracefully falls back to the latest block and logs a warning. Done when the script prints “⚠️ Requested block not found, using latest block < number >” and continues without throwing.
Your tasks this week
Do the exercises above before the next chapter. Reading a tutorial and doing
one are different activities and only one of them changes what you can build.
Stuck on any of them? Say so — describe what you tried and what happened:
tell me where you got stuck. I read every one, and the questions
that come back more than twice get answered in the next chapter.
The blockchain bootcamp
Chapter 1 of 18. New chapter every Saturday evening.
Next: Wallets, keys and addresses.
· The full syllabus and every chapter so far
· Subscribers also get the condensed notes for this chapter, the running
recap of everything the series has covered, and the extended guidance:
subscribe
Written by Amit Chakraborty — founding engineer and senior architect: React Native, AI and RAG systems, production architecture. Portfolio · LinkedIn · GitHub.
Need this built, reviewed or taught to your team? Get in touch or email amit@devamit.co.in. Available for senior and founding engineering roles, consulting and training, remote worldwide.
Top comments (0)