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
- Block: The fundamental unit of a blockchain that contains data, a timestamp, a hash of the previous block, and its own hash.
- Blockchain: A collection of blocks that are linked together in a specific order.
- Hashing: The process of generating a fixed-size string of characters (a hash) from data, which serves as a unique identifier for that data.
- 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
}
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
}
Adding Blocks
New blocks can be added to the blockchain using the AddBlock method. This method performs the following steps:
- Locks the blockchain for safe concurrent access.
- Creates a new block based on the previous block's hash.
- Uses a nonce to find a valid hash that meets the PoW requirement (in this case, the hash must start with five zeros).
- 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[:])
}
Running the Code
To run the blockchain implementation, follow these steps:
- Install Go: Ensure you have Go installed on your machine. If not, you can download it from golang.org.
- Create a new Go file: Copy the provided code into a new file named main.go. Run the application:
- Open a terminal and navigate to the directory containing your main.go file. Run the following command:
go run main.go
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
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()
}
}
Top comments (0)