package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"strconv"
"strings"
"time"
)
// Block represents a block in the blockchain
type Block struct {
Index int
Timestamp string
Data string
PrevHash string
Hash string
Nonce int
}
// Node represents a node in the network
type Node struct {
ID string
Blockchain []Block
}
// Calculates the SHA-256 hash of a block including its nonce
func calculateHash(block Block) string {
record := strconv.Itoa(block.Index) + block.Timestamp + block.Data + block.PrevHash + strconv.Itoa(block.Nonce)
hash := sha256.Sum256([]byte(record))
return hex.EncodeToString(hash[:])
}
// Proof of Work mining function
func mineBlock(block *Block, difficulty int) {
targetPrefix := strings.Repeat("0", difficulty)
for {
hash := calculateHash(*block)
if strings.HasPrefix(hash, targetPrefix) {
block.Hash = hash
return
}
block.Nonce++
}
}
// Creates the first block (genesis block)
func generateGenesisBlock(difficulty int) Block {
block := Block{
Index: 0,
Timestamp: time.Now().String(),
Data: "Genesis Block",
PrevHash: "",
}
mineBlock(█, difficulty)
return block
}
// Mines and returns the next block based on the previous one
func mineNewBlock(prevBlock Block, data string, difficulty int) Block {
newBlock := Block{
Index: prevBlock.Index + 1,
Timestamp: time.Now().String(),
Data: data,
PrevHash: prevBlock.Hash,
}
mineBlock(&newBlock, difficulty)
return newBlock
}
// Validates a full blockchain (links and hashes must match)
func isValidChain(chain []Block) bool {
for i := 1; i < len(chain); i++ {
prev := chain[i-1]
curr := chain[i]
if curr.PrevHash != prev.Hash {
return false
}
if calculateHash(curr) != curr.Hash {
return false
}
}
return true
}
// Simulates consensus: adopt the longest valid chain from neighbors
func resolveConflict(node *Node, neighbors []*Node) {
maxLength := len(node.Blockchain)
var longestChain []Block
for _, peer := range neighbors {
if isValidChain(peer.Blockchain) && len(peer.Blockchain) > maxLength {
maxLength = len(peer.Blockchain)
longestChain = peer.Blockchain
}
}
if longestChain != nil {
node.Blockchain = longestChain
fmt.Printf("Node %s adopted a longer chain from peers.\n", node.ID)
}
}
// Display the chain for debugging or verification
func printChain(node *Node) {
fmt.Printf("\nBlockchain at node %s:\n", node.ID)
for _, block := range node.Blockchain {
fmt.Printf("Index: %d, Nonce: %d, Hash: %s\n", block.Index, block.Nonce, block.Hash)
}
}
func main() {
difficulty := 3
// Genesis block shared across all nodes
genesis := generateGenesisBlock(difficulty)
// Simulate three nodes in a network
nodeA := &Node{ID: "A", Blockchain: []Block{genesis}}
nodeB := &Node{ID: "B", Blockchain: []Block{genesis}}
nodeC := &Node{ID: "C", Blockchain: []Block{genesis}}
// Node A mines 2 blocks
nodeA.Blockchain = append(nodeA.Blockchain, mineNewBlock(nodeA.Blockchain[len(nodeA.Blockchain)-1], "Tx A1", difficulty))
nodeA.Blockchain = append(nodeA.Blockchain, mineNewBlock(nodeA.Blockchain[len(nodeA.Blockchain)-1], "Tx A2", difficulty))
// Node B mines 1 block
nodeB.Blockchain = append(nodeB.Blockchain, mineNewBlock(nodeB.Blockchain[len(nodeB.Blockchain)-1], "Tx B1", difficulty))
// Node C receives chains from A and B, and adopts the longest valid one
neighbors := []*Node{nodeA, nodeB}
resolveConflict(nodeC, neighbors)
// Print results
printChain(nodeA)
printChain(nodeB)
printChain(nodeC)
}
What We Simulated
Node A had the longest chain.
Node C accepted Node A’s chain over Node B’s.
Consensus was reached: everyone trusts the longest valid chain.
This is a simplified version of how Bitcoin nodes operate: trust the chain with the most work behind it.
Consensus in the Real World
Benefits:
- Tolerance to node failure or delay
- No central authority required
- Secure against malicious actors (up to a point)
Limitations:
- Proof of Work is energy-intensive
- Finality (when a block is truly irreversible) can be slow
- Forks and chain reorganizations can occur