Skip to content

Instantly share code, notes, and snippets.

@agambondan
Created May 9, 2023 07:09
Show Gist options
  • Save agambondan/036ab4dceed50b008558c2aae1aea581 to your computer and use it in GitHub Desktop.
Save agambondan/036ab4dceed50b008558c2aae1aea581 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"crypto/sha256"
"fmt"
"math"
"math/big"
"strconv"
"time"
)
type Block struct {
Timestamp int64
Data []byte
PrevBlockHash []byte
Nonce int
Hash []byte
}
type Blockchain struct {
Blocks []*Block
}
func NewBlock(data string, prevBlockHash []byte) *Block {
block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, 0, []byte{}}
pow := NewProofOfWork(block)
nonce, hash := pow.Run()
block.Hash = hash[:]
block.Nonce = nonce
return block
}
func NewBlockchain() *Blockchain {
genesisBlock := NewBlock("Genesis Block", []byte{})
blockchain := &Blockchain{[]*Block{genesisBlock}}
return blockchain
}
func (bc *Blockchain) AddBlock(data string) {
prevBlock := bc.Blocks[len(bc.Blocks)-1]
newBlock := NewBlock(data, prevBlock.Hash)
bc.Blocks = append(bc.Blocks, newBlock)
}
type ProofOfWork struct {
Block *Block
Target *big.Int
}
func NewProofOfWork(block *Block) *ProofOfWork {
target := big.NewInt(1)
target.Lsh(target, uint(256-Difficulty))
pow := &ProofOfWork{block, target}
return pow
}
func (pow *ProofOfWork) Run() (int, []byte) {
var hashInt big.Int
var hash [32]byte
nonce := 0
for nonce < MaxNonce {
data := pow.prepareData(nonce)
hash = sha256.Sum256(data)
fmt.Printf("\r%x", hash)
hashInt.SetBytes(hash[:])
if hashInt.Cmp(pow.Target) == -1 {
break
} else {
nonce++
}
}
fmt.Println()
return nonce, hash[:]
}
func (pow *ProofOfWork) prepareData(nonce int) []byte {
data := bytes.Join(
[][]byte{
pow.Block.PrevBlockHash,
pow.Block.Data,
IntToHex(pow.Block.Timestamp),
IntToHex(int64(Difficulty)),
IntToHex(int64(nonce)),
},
[]byte{},
)
return data
}
const (
Difficulty = 18
MaxNonce = math.MaxInt64
)
func IntToHex(n int64) []byte {
return []byte(strconv.FormatInt(n, 16))
}
func main() {
bc := NewBlockchain()
bc.AddBlock("Block 1")
bc.AddBlock("Block 2")
bc.AddBlock("Block 3")
for _, block := range bc.Blocks {
fmt.Printf("Timestamp: %d\n", block.Timestamp)
fmt.Printf("Data: %s\n", block.Data)
fmt.Printf("PrevBlockHash: %x\n", block.PrevBlockHash)
fmt.Printf("Hash: %x\n", block.Hash)
fmt.Printf("Nonce: %d\n", block.Nonce)
fmt.Println()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment