Skip to content

Instantly share code, notes, and snippets.

@usbuild
Last active May 27, 2022 11:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save usbuild/d6a9668d9cd2b0f5ead86f19ef6ef6b6 to your computer and use it in GitHub Desktop.
Save usbuild/d6a9668d9cd2b0f5ead86f19ef6ef6b6 to your computer and use it in GitHub Desktop.
simple implementation of blockchain
package blockchain
import (
"time"
"crypto/sha256"
"encoding/binary"
"bytes"
"fmt"
)
type Block struct {
index int64
timestamp int64
transactions []*Transaction
previous_hash []byte
merkle_root []byte
nonce int64
}
type Transaction struct {
sender string
recipient string
amount int64
}
type Blockchain struct {
chain []*Block
current_transactions []*Transaction
}
func New() *Blockchain {
bc := new(Blockchain)
bc.chain = make([]*Block, 0, 100)
bc.newBlockWithHash([]byte{})
return bc
}
func hash(block *Block) []byte {
var buf bytes.Buffer
binary.Write(&buf, binary.BigEndian, block.index)
binary.Write(&buf, binary.BigEndian, block.timestamp)
binary.Write(&buf, binary.BigEndian, block.previous_hash)
binary.Write(&buf, binary.BigEndian, block.merkle_root)
binary.Write(&buf, binary.BigEndian, block.nonce)
ret := sha256.Sum256(buf.Bytes())
return ret[:]
}
func validBlock(block *Block) bool {
zeros := int(block.index / 100 + 1)
guess_hash := hash(block)
for i := 0; i < zeros; i++ {
if guess_hash[i] != 0 {
return false
}
}
return true
}
func calcMerkleRoot(transactions []*Transaction) []byte {
if len(transactions) == 0 {
return []byte{}
}
data := make([][]byte, 0, len(transactions) / 2 + 1)
var buf bytes.Buffer
for i := 0; i < len(transactions); i++ {
binary.Write(&buf, binary.BigEndian, []byte(transactions[i].sender))
binary.Write(&buf, binary.BigEndian, []byte(transactions[i].recipient))
binary.Write(&buf, binary.BigEndian, transactions[i].amount)
sum := sha256.Sum256(buf.Bytes())
data = append(data, sum[:])
}
for ;len(data) != 1; data = data[: (len(data) + 1) / 2]{
h := sha256.New()
for i := 0; i < len(data); i += 2 {
j := i / 2
if i + 1 >= len(data) {
data[j] = data[i]
} else {
h.Reset()
h.Write(data[i])
h.Write(data[j])
data[j] = h.Sum(nil)
}
}
}
return data[0]
}
func (self *Blockchain) newBlockWithHash(previous_hash []byte) *Block{
block := Block{
index: int64(len(self.chain) + 1),
timestamp: int64(time.Now().Unix()),
transactions: self.current_transactions,
previous_hash: previous_hash,
nonce: 0,
merkle_root: calcMerkleRoot(self.current_transactions),
}
for ; !validBlock(&block); block.nonce++ {}
self.current_transactions = make([]*Transaction, 0, 100)
self.chain = append(self.chain, &block)
return &block
}
func (self *Blockchain) commitBlock() *Block{
return self.newBlockWithHash(hash(self.lastBlock()))
}
func (self *Blockchain) lastBlock() *Block {
return self.chain[len(self.chain) - 1]
}
func (self *Blockchain) NewTransaction(sender string, recipient string, amount int64) int64 {
self.current_transactions = append(self.current_transactions, &Transaction{sender: sender, recipient: recipient, amount: amount})
return self.lastBlock().index + 1
}
func (self *Blockchain) Mine() string{
self.NewTransaction("", "me", 1)
block := self.commitBlock()
return fmt.Sprintf("%+v", block)
}
func (self *Blockchain) Print() {
fmt.Printf("%+v\n", self)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment