Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Before smart contracts, validators, or wallets, a blockchain is one data structure: a singly-linked list where each node embeds the hash of the previous node. Understanding this structure in 20 lines of Python is the single best anchor for every later concept — gas, finality, reorgs, light clients all trace back to the fact that each block commits to its predecessor.
We'll build three blocks where each block's content includes the SHA-256 of the previous block. The output will show that block 2's prev equals the hash of block 1's content, and so on. Run it, then inspect the dict — you're looking at the core abstraction behind every chain in production.
prev field. Hash block 2 by hand (paste its JSON into an online SHA-256 tool) and verify you get the same value.data in the list — notice nothing recomputes downstream because we stored the hash already. This is the key insight.prev. Now you're one step away from validating the chain on reload.// main.go
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"sort"
)
type Block struct {
I int `json:"i"`
Data string `json:"data"`
Prev string `json:"prev"`
}
// h deterministically serialises the block (keys sorted) and returns its SHA-256 hex digest.
func h(b Block) string {
// json.Marshal already sorts struct fields by field-tag order, but we want
// explicit key-sorted output identical to Python's json.dumps(sort_keys=True).
m := map[string]interface{}{"i": b.I, "data": b.Data, "prev": b.Prev}
keys := []string{"data", "i", "prev"}
sort.Strings(keys)
ordered := make([]byte, 0, 64)
ordered = append(ordered, '{')
for idx, k := range keys {
if idx > 0 {
ordered = append(ordered, ',')
}
kb, _ := json.Marshal(k)
vb, _ := json.Marshal(m[k])
ordered = append(ordered, kb...)
ordered = append(ordered, ':')
ordered = append(ordered, vb...)
}
ordered = append(ordered, '}')
sum := sha256.Sum256(ordered)
return hex.EncodeToString(sum[:])
}
func main() {
blocks := []Block{{I: 0, Data: "genesis", Prev: "0000000000000000000000000000000000000000000000000000000000000000"}}
for i := 1; i < 4; i++ {
prevHash := h(blocks[len(blocks)-1])
blocks = append(blocks, Block{I: i, Data: fmt.Sprintf("tx-%d", i), Prev: prevHash})
}
for _, b := range blocks {
prev := b.Prev
if len(prev) > 12 {
prev = prev[:12] + "\u2026"
}
fmt.Println(b.I, b.Data, "prev="+prev)
}
_ = log.Writer() // satisfy import
}
go run main.go