DEV Community

Cover image for The blockchain bootcamp · 1. The vocabulary
Amit chakraborty
Amit chakraborty

Posted on Originally published at amitchakraborty.dev

The blockchain bootcamp · 1. The vocabulary

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 -v should output v20.x.x.
  • npm 10.2.3 – npm -v should output 10.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}`));
Enter fullscreen mode Exit fullscreen mode

Run node check.js. You should see something like:

Latest block: 19784234
Enter fullscreen mode Exit fullscreen mode

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:

  1. Collision resistance – finding two different inputs with the same hash is computationally infeasible.
  2. Pre‑image resistance – given a hash, it is infeasible to reconstruct the original input.
  3. 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:

  1. Assemble the block header (including the current nonce).
  2. Compute hash = keccak256(header).
  3. Compare hash to target. If hash < target, the block is valid; otherwise, increment nonce and 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).

  1. Create the project folder
   mkdir eth-vocab-demo && cd eth-vocab-demo
   npm init -y
   npm i ethers@6.7.0
Enter fullscreen mode Exit fullscreen mode

Why: isolates the demo and ensures the correct ethers version.

  1. 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);
   });
Enter fullscreen mode Exit fullscreen mode

Why: The script demonstrates each term in context, and the low‑level RPC call shows how finality is exposed.

  1. Run the script
   node blockInfo.js
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

  1. 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);
   })();"
Enter fullscreen mode Exit fullscreen mode

Expected output:

   Parent hash matches? true
Enter fullscreen mode Exit fullscreen mode

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

  1. Identify block fields

    Using the script from Build it, copy the JSON output of a block (run node -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 for number, hash, parentHash, timestamp, nonce, and stateRoot. Verify that parentHash matches the hash of the previous block by fetching the predecessor. Done when both hashes match exactly.

  2. Compute a block header hash manually

    Install keccak256 (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 the hash field from the RPC. Done when the two hex strings are identical.

  3. 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).

  4. 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 the finalized flag 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 the finalized flag and explains the trade‑off.

  5. 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)