Skip to content

Commit

Permalink
refactor: proof of work implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
stinkymonkeyph committed Aug 4, 2024
1 parent a4c78a1 commit 46b1d65
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 49 deletions.
17 changes: 10 additions & 7 deletions blockchain/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,16 @@ func (b *Block) Hash() string {
}

func (b *Block) AddTransactionToTheBlock(txn *Transaction) {
isValid := txn.VerifyTransaction()
if txn.Status == constants.STATUS_PENDING {
isValid := txn.VerifyTransaction()

if isValid {
txn.Status = constants.STATUS_SUCCESS
} else {
txn.Status = constants.STATUS_FAILED
}
if isValid {
txn.Status = constants.STATUS_SUCCESS
} else {
txn.Status = constants.STATUS_FAILED
}

b.Transactions = append(b.Transactions, txn)

b.Transactions = append(b.Transactions, txn)
}
}
97 changes: 66 additions & 31 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import (
type Blockchain struct {
TransactionPool []*Transaction `json:"transaction_pool"`
Blocks []*Block `json:"block_chain"`
WalletIndex *WalletIndex
}

func (bc *Blockchain) Airdrop(address string) {
txn := NewTransaction(constants.BLOCKCHAIN_AIRDROP_ADDRESS, address, constants.AIRDROP_AMOUNT, []byte{})
bc.AddTransactionToTransactionPool(txn)
}

func NewBlockchain(genesisBlock *Block) *Blockchain {
Expand All @@ -19,22 +25,28 @@ func NewBlockchain(genesisBlock *Block) *Blockchain {

if err != nil {
bc = new(Blockchain)
bc.TransactionPool = []*Transaction{}
bc.Blocks = append(bc.Blocks, genesisBlock)
bc.WalletIndex = NewWalletIndex()
err := PutIntoDb(bc)

if err != nil {
log.Panicf(err.Error())
}

} else {
log.Println("Found existing blockchain state, persisting state from datastore")
bc = &state
}

bc.TransactionPool = []*Transaction{}
bc.Blocks = append(bc.Blocks, genesisBlock)

return bc
}

func (bc *Blockchain) ToJSON() string {
bbc, err := json.Marshal(bc)

if err != nil {
panic("Something went wrong while serializing blockchain object")
log.Panic(err.Error())
}

return string(bbc)
Expand All @@ -43,12 +55,23 @@ func (bc *Blockchain) ToJSON() string {
func (bc *Blockchain) AddTransactionToTransactionPool(txn *Transaction) {
txn.Status = constants.STATUS_PENDING
bc.TransactionPool = append(bc.TransactionPool, txn)
err := PutIntoDb(bc)
if err != nil {
log.Default().Panicf(err.Error())
}
}

func (bc *Blockchain) AddBlock(b *Block) {
m := map[string]bool{}
for _, txn := range b.Transactions {

nextBlockHeight := len(bc.Blocks)

for index, txn := range b.Transactions {
m[txn.TransactioHash] = true
balance := bc.WalletIndex.CalculateBalance(txn.From)
log.Printf("\n\nsender balance -> %d \n\n", balance)
bc.WalletIndex.AddTransaction(txn.From, nextBlockHeight, index, txn)
bc.WalletIndex.AddTransaction(txn.To, nextBlockHeight, index, txn)
}

for idx, txn := range bc.TransactionPool {
Expand All @@ -64,36 +87,48 @@ func (bc *Blockchain) AddBlock(b *Block) {
err := PutIntoDb(bc)

if err != nil {
log.Panicf("Something went wrong while saving state to database, halting entire process %s", err)
log.Panic(err.Error())
}
}

func (bc *Blockchain) ProofOfWorkMining(minerAddress string) {
func (bc *Blockchain) LastBlock() *Block {
return bc.Blocks[len(bc.Blocks)-1]
}

func (bc *Blockchain) CopyTransactionPool() []*Transaction {
t := make([]*Transaction, 0)
for _, txn := range bc.TransactionPool {
t = append(t, NewTransaction(txn.From, txn.To, txn.Value, txn.Data))
}
return t
}

func (bc *Blockchain) ValidProof(nonce int, previousHash string, transactions []*Transaction, difficulty int) bool {
zeroes := strings.Repeat("0", difficulty)
guessBlock := &Block{PrevHash: previousHash, Timestamp: 0, Nonce: nonce, Transactions: transactions}
guessHash := guessBlock.Hash()
return zeroes == guessHash[2:2+constants.MINING_DIFFICULTY]
}

func (bc *Blockchain) ProofOfWork() (int, []*Transaction) {
t := bc.CopyTransactionPool()
previousHash := bc.LastBlock().Hash()
nonce := 0
log.Println("Starting Proof of Work")
for {
prevHash := bc.Blocks[len(bc.Blocks)-1].Hash()
guessBlock := NewBlock(prevHash, nonce)

for _, txn := range bc.TransactionPool {
tx := NewTransaction(txn.From, txn.To, txn.Value, txn.Data)
guessBlock.AddTransactionToTheBlock(tx)
}

zeroes := strings.Repeat("0", constants.MINING_DIFFICULTY)
guessHash := guessBlock.Hash()

if zeroes == guessHash[2:2+constants.MINING_DIFFICULTY] {
log.Println("Found solution")
log.Printf("Mining Difficulty is %d", constants.MINING_DIFFICULTY)
log.Printf("Hash Solution: %s", guessHash)
rewardTxn := NewTransaction(constants.BLOCKCHAIN_REWARD_ADDRESS, minerAddress, constants.MINING_REWARD, []byte{})
rewardTxn.Status = constants.STATUS_SUCCESS
guessBlock.Transactions = append(guessBlock.Transactions, rewardTxn)
bc.AddBlock(guessBlock)
log.Printf("%s \n\n", bc.ToJSON())
nonce = 0
continue
}
for !bc.ValidProof(nonce, previousHash, t, constants.MINING_DIFFICULTY) {
nonce += 1
}

return nonce, t
}

func (bc *Blockchain) Mining() bool {
log.Println("Start proof of work")
nonce, txns := bc.ProofOfWork()
previousHash := bc.LastBlock().Hash()
block := NewBlock(previousHash, nonce)
block.Transactions = txns
bc.AddBlock(block)
log.Println("Found solution")
return true
}
6 changes: 5 additions & 1 deletion constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ const (
STATUS_SUCCESS = "success"
STATUS_FAILED = "failed"
STATUS_PENDING = "pending"
MINING_DIFFICULTY = 5
MINING_DIFFICULTY = 3
MINING_REWARD = 1200 * DECIMAL
CURRENCY_NAME = "gopher"
DECIMAL = 100
BLOCKCHAIN_REWARD_ADDRESS = "Gopher_Reward_Pool"
DB_PATH = "./data"
DB_KEY = "blockchain_data"
//temporary airdrop distribution for sender wallet since tx will fail because balance is 0 for sender wallets
AIRDROP_AMOUNT = 100
AIRDROP_ROUND = 1
BLOCKCHAIN_AIRDROP_ADDRESS = "Gopher_Airdrop_Pool"
)
17 changes: 7 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package main

import (
"log"
"sync"
"time"

"github.com/stinkymonkeyph/gopher-blocks/blockchain"
"github.com/stinkymonkeyph/gopher-blocks/constants"
Expand All @@ -14,17 +12,16 @@ func init() {
}

func main() {

var wg sync.WaitGroup

block := blockchain.NewBlock("0x0", 0)
transaction1 := blockchain.NewTransaction("0x1", "0x2", 12, []byte{})
bc := blockchain.NewBlockchain(block)
bc.Airdrop("0x1")
bc.Mining()
log.Print(bc.ToJSON())

wg.Add(1)
go bc.ProofOfWorkMining("alice")
time.Sleep(2000)
transaction1 := blockchain.NewTransaction("0x1", "0x2", 12, []byte{})
bc.AddTransactionToTransactionPool(transaction1)
wg.Wait()
bc.Mining()
log.Print(bc.ToJSON())
senderBalance := bc.WalletIndex.CalculateBalance("0x1")
log.Printf("\n\n\nSender Balance: %d \n", senderBalance)
}

0 comments on commit 46b1d65

Please sign in to comment.