This is the demo project for implementaion blockchain concept with golang
type Block struct {
Hash []byte
Data []byte
PrevHash []byte
}
type BlockChain struct {
blocks []*Block
}
func (b *Block) DeriveHash() {
info := bytes.Join([][]byte{b.Data, b.PrevHash}, []byte{})
hash := sha256.Sum256(info)
b.Hash = hash[:]
}
func CreateBlock(data string, prevHash []byte) *Block {
block := &Block{[]byte{}, []byte(data), prevHash}
block.DeriveHash()
return block
}
func Genesis() *Block {
return CreateBlock("Genesis", []byte{})
}
func (chain *BlockChain) AddBlock(data string) {
prevBlock := chain.blocks[len(chain.blocks)-1]
new := CreateBlock(data, prevBlock.Hash)
chain.blocks = append(chain.blocks, new)
}
func InitBlockChain() *BlockChain {
return &BlockChain{[]*Block{Genesis()}}
}
// Take the data from the block
// create a counter (nonce) with starts at 0
// create a hash of the data plus the counter
// check the hash to see if it meets a set of requirements
// Requiremenets:
// The First few bytes must containe 0s
const Difficulty = 18
type ProofOfWork struct {
Block *Block
Target *big.Int
}
func (pow *ProofOfWork) Validate() bool {
var intHash big.Int
data := pow.InitData(pow.Block.Nonce)
hash := sha256.Sum256(data)
intHash.SetBytes(hash[:])
return intHash.Cmp(pow.Target) == -1
}
func (pow *ProofOfWork) Run() (int, []byte) {
var intHash big.Int
var hash [32]byte
nonce := 0
for nonce < math.MaxInt64 {
data := pow.InitData(nonce)
hash = sha256.Sum256(data)
fmt.Printf("\r%x", hash)
intHash.SetBytes(hash[:])
if intHash.Cmp(pow.Target) == -1 {
break
} else {
nonce++
}
}
fmt.Println()
return nonce, hash[:]
}
func NewProof(b *Block) *ProofOfWork {
target := big.NewInt(1)
target.Lsh(target, uint(256-Difficulty))
pow := &ProofOfWork{b, target}
return pow
}
func (pow *ProofOfWork) InitData(nonce int) []byte {
data := bytes.Join(
[][]byte{
pow.Block.PrevHash,
pow.Block.Data,
ToHex(int64(nonce)),
ToHex(int64(Difficulty)),
},
[]byte{},
)
return data
}
func ToHex(num int64) []byte {
buff := new(bytes.Buffer)
err := binary.Write(buff, binary.BigEndian, num)
if err != nil {
log.Panic(err)
}
return buff.Bytes()
}