Skip to content

Instantly share code, notes, and snippets.

@shekohex
Created December 23, 2017 20:58
Show Gist options
  • Save shekohex/9da2c116ca2a1209c5851f955bd24a6c to your computer and use it in GitHub Desktop.
Save shekohex/9da2c116ca2a1209c5851f955bd24a6c to your computer and use it in GitHub Desktop.
Simple Block Chain Mechanism in Go for Learning Purpose
package main
import (
"crypto/sha256"
"encoding/json"
"fmt"
"strings"
)
// Data ...
type Data struct {
amount int
msg string
}
// Block ...
type Block struct {
nonce int
hash string
index int
ts string
data Data
previousHash string
}
// CreateBlock ...
func CreateBlock(index int, ts string, data Data) *Block {
block := new(Block)
block.index = index
block.data = data
block.ts = ts
block.nonce = 0
block.previousHash = ""
calculateHash(block)
return block
}
// Mine ...
func Mine(difficulty int, block *Block) bool {
zeros := make([]int, difficulty, difficulty) // create an array of zeros for difficulty
zerosStr := strings.Trim(strings.Join(strings.Split(fmt.Sprint(zeros), " "), ""), "[]") // convert it to string
for !strings.HasPrefix(block.hash, zerosStr) {
block.nonce++
fmt.Printf("\u2717: \x1b[31m%s\x1b[0m\n", block.hash)
calculateHash(block)
}
fmt.Printf("\u2713: \x1b[32m%s\x1b[0m\n", block.hash)
return true
}
func calculateHash(block *Block) {
h := sha256.New()
out, err := json.Marshal(fmt.Sprintf("%s", block))
if err != nil {
panic(err)
}
h.Write([]byte(string(out)))
block.hash = fmt.Sprintf("%x", h.Sum(nil))
}
package main
import (
"fmt"
"time"
)
// BlockChain ...
type BlockChain struct {
difficulty int
blocks []*Block
}
// CreateChain ...
func (chain *BlockChain) CreateChain() *BlockChain {
chain.difficulty = 4
block1 := CreateBlock(0, time.Now().String(), Data{0, "0"})
chain.blocks = append(chain.blocks, block1)
return chain
}
// AddBlock ...
func (chain *BlockChain) AddBlock(block *Block) {
block.previousHash = getLatestBlock(chain).hash
Mine(chain.difficulty, block)
chain.blocks = append(chain.blocks, block)
}
// Add ...
func (chain *BlockChain) Add(blocks []Block) {
for i := range blocks {
block := blocks[i]
block.previousHash = getLatestBlock(chain).hash
Mine(chain.difficulty, &block)
if !chain.isChainValid() {
chain.blocks = chain.blocks[:len(chain.blocks)-1] // remove it
} else {
chain.blocks = append(chain.blocks, &block)
}
}
}
// Print ...
func (chain BlockChain) Print() {
for _, b := range chain.blocks {
fmt.Printf("%+v\n", b)
}
}
func getLatestBlock(chain *BlockChain) *Block {
return chain.blocks[len(chain.blocks)-1]
}
func (chain *BlockChain) isChainValid() bool {
for i := 1; i <= len(chain.blocks)-1; i++ {
currentBlock := chain.blocks[i]
previousBlock := chain.blocks[i-1]
if currentBlock.previousHash != previousBlock.hash {
return false
}
}
return true
}
package main
import (
"fmt"
"time"
)
func main() {
data1 := Data{1, "12133"}
block1 := CreateBlock(1, time.Now().String(), data1)
data2 := Data{1, "1223"}
block2 := CreateBlock(2, time.Now().String(), data2)
data3 := Data{1, "1123"}
block3 := CreateBlock(3, time.Now().String(), data3)
chain := new(BlockChain)
chain.CreateChain()
chain.AddBlock(block1)
chain.AddBlock(block2)
chain.AddBlock(block3)
chain.Print()
fmt.Println(chain.isChainValid())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment