Created
December 23, 2017 20:58
-
-
Save shekohex/9da2c116ca2a1209c5851f955bd24a6c to your computer and use it in GitHub Desktop.
Simple Block Chain Mechanism in Go for Learning Purpose
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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