What Is a Blockchain? Build a Mini One in Go

Blockchain has become one of the most exciting technologies of the 21st century, powering cryptocurrencies, smart contracts, supply chain tracking, and more. But what is a blockchain, really?

In this article, we’ll demystify the concept by building a simple blockchain from scratch using Go. No crypto libraries, no external frameworks—just Go’s standard packages and a few dozen lines of code.

By the end, you’ll understand how blocks are linked together using hashes, and you’ll have a working toy blockchain to play with.

What Is a Blockchain?

At its core, a blockchain is:

  • A chain of blocks
  • Each block contains data and a cryptographic hash
  • Each block references the hash of the previous block

This creates an immutable ledger—if someone tampers with a previous block, all the following hashes break. This structure is what gives blockchain its integrity.

Let’s visualize it:

[Block 0] --> [Block 1] --> [Block 2] --> ...
    |             |             |
  Hash 0      Prev:Hash 0   Prev:Hash 1

Each block contains:

  • An index (its position in the chain)
  • A timestamp
  • Some data (like transactions)
  • The hash of the previous block
  • Its own hash (calculated from its content)
Building a Simple Blockchain in Go

See the next section.

Go example

type Block struct {
    Index        int
    Timestamp    string
    Data         string
    PrevHash     string
    Hash         string
}
func calculateHash(block Block) string {
  record := strconv.Itoa(block.Index) + block.Timestamp + block.Data + block.PrevHash
  h := sha256.New()
  h.Write([]byte(record))
  return hex.EncodeToString(h.Sum(nil))
}
func createGenesisBlock() Block {
  genesis := Block{0, time.Now().String(), "Genesis Block", "", ""}
  genesis.Hash = calculateHash(genesis)
  return genesis
}
func generateNextBlock(prevBlock Block, data string) Block {
  newBlock := Block{
      Index:     prevBlock.Index + 1,
      Timestamp: time.Now().String(),
      Data:      data,
      PrevHash:  prevBlock.Hash,
  }
  newBlock.Hash = calculateHash(newBlock)
  return newBlock
}
func main() {
  var blockchain []Block

  genesis := createGenesisBlock()
  blockchain = append(blockchain, genesis)

  for i := 1; i <= 5; i++ {
      newBlock := generateNextBlock(blockchain[len(blockchain)-1], fmt.Sprintf("Block #%d data", i))
      blockchain = append(blockchain, newBlock)
  }

  for _, block := range blockchain {
      fmt.Printf("Index: %d\nTimestamp: %s\nData: %s\nPrevHash: %s\nHash: %s\n\n",
          block.Index, block.Timestamp, block.Data, block.PrevHash, block.Hash)
  }
}

Here is what the output should look like:

Index: 0
Timestamp: 2025-04-14 12:34:56
Data: Genesis Block
PrevHash:
Hash: 2a7c...a3e9

Index: 1
Timestamp: 2025-04-14 12:35:01
Data: Block #1 data
PrevHash: 2a7c...a3e9
Hash: e7fd...1d3b
... 

Each block clearly links to the one before it. If any block is modified, the hashes no longer match — making tampering obvious and easily detectable.