DEV Community

Smally Pauls
Smally Pauls

Posted on

Simple Blockchain Implementation in Go

Golang Blockchain

Overview

This project demonstrates a simplified version of a blockchain implemented in Go. It showcases the fundamental concepts of blockchain technology, including blocks, hashing, and proof of work (PoW). The implementation allows users to create a chain of blocks, each containing data, a timestamp, a reference to the previous block, and a cryptographic hash.

Table of Contents

What is a Blockchain?

A blockchain is a decentralized digital ledger that records transactions across many computers in such a way that the registered transactions cannot be altered retroactively. Each block contains a list of transactions and is linked to the previous block, forming a chain. This structure makes blockchains resistant to modification and fraud.

Key Components

  1. Block: The fundamental unit of a blockchain that contains data, a timestamp, a hash of the previous block, and its own hash.
  2. Blockchain: A collection of blocks that are linked together in a specific order.
  3. Hashing: The process of generating a fixed-size string of characters (a hash) from data, which serves as a unique identifier for that data.
  4. Proof of Work (PoW): A consensus mechanism used to validate new blocks by requiring computational effort to generate a valid hash.

How the Code Works

Block Structure

The Block struct represents an individual block in the blockchain with the following fields:

  • ID: The unique identifier for the block.
  • Data: The information stored in the block.
  • TimeStamp: The time at which the block was created.
  • PreHash: The hash of the previous block in the chain.
  • Hash: The hash of the current block.
  • Nonce: A variable used in the PoW algorithm to find a valid hash.

Blockchain Structure

The Blockchain struct holds a slice of Block objects and a mutex for safe concurrent access:

type Blockchain struct {
    Blocks []Block
    mu     sync.Mutex
}
Enter fullscreen mode Exit fullscreen mode

Creating the Genesis Block

The first block in the blockchain is called the "genesis block." It is created with a specific structure and serves as the foundation for the subsequent blocks:

func GenesisBlock() Block {
    genesis := Block{0, "Genesis Block", time.Now().String(), "", "", 0}
    genesis.Hash = genesis.CreateHash()
    return genesis
}
Enter fullscreen mode Exit fullscreen mode

Adding Blocks

New blocks can be added to the blockchain using the AddBlock method. This method performs the following steps:

  1. Locks the blockchain for safe concurrent access.
  2. Creates a new block based on the previous block's hash.
  3. Uses a nonce to find a valid hash that meets the PoW requirement (in this case, the hash must start with five zeros).
  4. Validates the new block and appends it to the blockchain.

Hashing and Validating Blocks

The CreateHash method generates a hash for the block using SHA-256, and the IsValidHash function checks if the hash meets the criteria for PoW.

func (b *Block) CreateHash() string {
    res := strconv.Itoa(b.ID) + b.Data + b.TimeStamp + b.PreHash + b.Hash
    hash := sha256.Sum256([]byte(res))
    return hex.EncodeToString(hash[:])
}
Enter fullscreen mode Exit fullscreen mode

Running the Code

To run the blockchain implementation, follow these steps:

  1. Install Go: Ensure you have Go installed on your machine. If not, you can download it from golang.org.
  2. Create a new Go file: Copy the provided code into a new file named main.go. Run the application:
  3. Open a terminal and navigate to the directory containing your main.go file. Run the following command:
go run main.go
Enter fullscreen mode Exit fullscreen mode

Expected output

Index: 0
Timestamp: 2024-10-12 04:07:46.335461011 +0300 EAT m=+0.000031916
Data: Genesis Block
PrevHash: 
Hash: ca1dd92e0c1abbdeb695d9f526bac0e8c2b23d2471eeb255098aaa5b1b36773b
Nonce: 0

Index: 1
Timestamp: 2024-10-12 04:07:46.335570999 +0300 EAT m=+0.000141904
Data: second block
PrevHash: ca1dd92e0c1abbdeb695d9f526bac0e8c2b23d2471eeb255098aaa5b1b36773b
Hash: 00000b52fe5bf3c81f1474d738dd8d299c35d2075987d80457780b8af18c1cb9
Nonce: 4401865

Index: 2
Timestamp: 2024-10-12 04:07:50.532612884 +0300 EAT m=+4.197183785
Data: third block
PrevHash: 00000b52fe5bf3c81f1474d738dd8d299c35d2075987d80457780b8af18c1cb9
Hash: 00000b5e6a6532387b11944a3b03bc62a46b340deb1844acbf0ba33100a4024c
Nonce: 143744

Index: 3
Timestamp: 2024-10-12 04:07:50.668087703 +0300 EAT m=+4.332658603
Data: forth block
PrevHash: 00000b5e6a6532387b11944a3b03bc62a46b340deb1844acbf0ba33100a4024c
Hash: 00000d179317e613a7fe14ca5cc2f5718709f747011a2eb5560754e5ee737593
Nonce: 148455

Index: 4
Timestamp: 2024-10-12 04:07:50.818969364 +0300 EAT m=+4.483540279
Data: fifth block
PrevHash: 00000d179317e613a7fe14ca5cc2f5718709f747011a2eb5560754e5ee737593
Hash: 0000015aeda3c490f10ffed0639fd39c9e570a8ad7208512a45372111304eecc
Nonce: 671069

Index: 5
Timestamp: 2024-10-12 04:07:51.492424149 +0300 EAT m=+5.156995064
Data: sixth block
PrevHash: 0000015aeda3c490f10ffed0639fd39c9e570a8ad7208512a45372111304eecc
Hash: 00000d5d3d9163702726ccbf967d2b99208c9f03b419788a826262e7a94b09ba
Nonce: 946880

Index: 6
Timestamp: 2024-10-12 04:07:52.478948177 +0300 EAT m=+6.143519089
Data: seventh block
PrevHash: 00000d5d3d9163702726ccbf967d2b99208c9f03b419788a826262e7a94b09ba
Hash: 00000c2bdb09d84493235c36058d4776fa35bafce141d4b095ab3af90fbcb10d
Nonce: 256130
Enter fullscreen mode Exit fullscreen mode

Conclusion

This simple blockchain implementation in Go demonstrates the core principles of blockchain technology, including block creation, hashing, and proof of work. While this example is simplified, it provides a foundational understanding of how blockchains work and can be expanded with additional features such as transaction handling, network protocols, and consensus mechanisms.

full Code

package main

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "log"
    "strconv"
    "sync"
    "time"
)

type Block struct {
    ID        int
    Data      string
    TimeStamp string
    PreHash   string
    Hash      string
    Nonce     int
}

type Blockchain struct {
    Blocks []Block
    mu     sync.Mutex
}

// function to create the hashing function
func (b *Block) CreateHash() string {
    res := strconv.Itoa(b.ID) + b.Data + b.TimeStamp + b.PreHash + b.Hash
    hash := sha256.Sum256([]byte(res))
    return hex.EncodeToString(hash[:])
}

// function to add a block for the blockchain
func (bc *Blockchain) AddBlock(data string) {
    bc.mu.Lock()
    defer bc.mu.Unlock()

    prevBlock := bc.Blocks[len(bc.Blocks)-1]
    newBlock := Block{
        ID:        prevBlock.ID + 1,
        Data:      data,
        TimeStamp: time.Now().String(),
        PreHash:   prevBlock.Hash,
    }

    for {
        newBlock.Hash = newBlock.CreateHash()
        if IsValidHash(newBlock.Hash) {
            break
        }
        newBlock.Nonce++
    }

    if bc.IsValidBlock(newBlock) {
        bc.Blocks = append(bc.Blocks, newBlock)
    } else {
        log.Fatalln("Invalid Block")
    }
}

// function to verify the PoW
func IsValidHash(hash string) bool {
    return hash[:5] == "00000"
}

// function to create genesis block
func GenesisBlock() Block {
    genesis := Block{0, "Genesis Block", time.Now().String(), "", "", 0}
    genesis.Hash = genesis.CreateHash()
    return genesis
}

// function to create a new blockchain
func CreateBlockchain() Blockchain {
    genesis := GenesisBlock()
    return Blockchain{Blocks: []Block{genesis}}
}

// function to verify the blocks
func (bc *Blockchain) IsValidBlock(block Block) bool {
    prevBlock := bc.Blocks[len(bc.Blocks)-1]
    if len(bc.Blocks) == 0 {
        return false
    }
    return prevBlock.Hash == block.PreHash
}

func main() {
    blockchain := CreateBlockchain()

    blockchain.AddBlock("second block")
    blockchain.AddBlock("third block")
    blockchain.AddBlock("forth block")
    blockchain.AddBlock("fifth block")
    blockchain.AddBlock("sixth block")
    blockchain.AddBlock("seventh block")

    for _, block := range blockchain.Blocks {
        fmt.Printf("Index: %d\n", block.ID)
        fmt.Printf("Timestamp: %s\n", block.TimeStamp)
        fmt.Printf("Data: %s\n", block.Data)
        fmt.Printf("PrevHash: %s\n", block.PreHash)
        fmt.Printf("Hash: %s\n", block.Hash)
        fmt.Printf("Nonce: %d\n", block.Nonce)
        fmt.Println()
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)