Skip to content

Instantly share code, notes, and snippets.

@LordGhostX
Last active March 27, 2024 20:34
Show Gist options
  • Save LordGhostX/bb92b907731ee8ebe465a28c5c431cb4 to your computer and use it in GitHub Desktop.
Save LordGhostX/bb92b907731ee8ebe465a28c5c431cb4 to your computer and use it in GitHub Desktop.
Blockchain POC with Golang
package main
import (
"crypto/sha256"
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
)
type Block struct {
data map[string]interface{}
hash string
previousHash string
timestamp time.Time
pow int
}
type Blockchain struct {
genesisBlock Block
chain []Block
difficulty int
}
func (b Block) calculateHash() string {
data, _ := json.Marshal(b.data)
blockData := b.previousHash + string(data) + b.timestamp.String() + strconv.Itoa(b.pow)
blockHash := sha256.Sum256([]byte(blockData))
return fmt.Sprintf("%x", blockHash)
}
func (b *Block) mine(difficulty int) {
for !strings.HasPrefix(b.hash, strings.Repeat("0", difficulty)) {
b.pow++
b.hash = b.calculateHash()
}
}
func CreateBlockchain(difficulty int) Blockchain {
genesisBlock := Block{
hash: "0",
timestamp: time.Now(),
}
return Blockchain{
genesisBlock,
[]Block{genesisBlock},
difficulty,
}
}
func (b *Blockchain) addBlock(from, to string, amount float64) {
blockData := map[string]interface{}{
"from": from,
"to": to,
"amount": amount,
}
lastBlock := b.chain[len(b.chain)-1]
newBlock := Block{
data: blockData,
previousHash: lastBlock.hash,
timestamp: time.Now(),
}
newBlock.mine(b.difficulty)
b.chain = append(b.chain, newBlock)
}
func (b Blockchain) isValid() bool {
for i := range b.chain[1:] {
previousBlock := b.chain[i]
currentBlock := b.chain[i+1]
if currentBlock.hash != currentBlock.calculateHash() || currentBlock.previousHash != previousBlock.hash {
return false
}
}
return true
}
func main() {
// create a new blockchain instance with a mining difficulty of 2
blockchain := CreateBlockchain(2)
// record transactions on the blockchain for Alice, Bob, and John
blockchain.addBlock("Alice", "Bob", 5)
blockchain.addBlock("John", "Bob", 2)
// check if the blockchain is valid; expecting true
fmt.Println(blockchain.isValid())
}
@LordGhostX
Copy link
Author

No it is not, feel free to use it as you wish.

@gaby
Copy link

gaby commented Dec 30, 2021

Awesome, thanks!

@ekpono
Copy link

ekpono commented Jan 1, 2022

I have hesitation learning Go since I am comfortable with PHP and Node. This is a nice intro though. Thanks

@ekpono
Copy link

ekpono commented Jan 1, 2022

@LordGhostX Any recommended tutorial?

@aNaoy
Copy link

aNaoy commented Jan 2, 2022

Great to learn the basics of blockchain while improving in Go! Thanks.

@FunnyGuy9796
Copy link

FunnyGuy9796 commented Jan 31, 2022

@LordGhostX How would I read the data of a block? Would I just do fmt.Println(blockchain.blockData)?

@goodylili
Copy link

@ekpono gobyexample.com is a very good resource. Also, learnxinyminutes if you're a speed learner.

@goodylili
Copy link

@LordGhostX how do i learn the concepts taught in this tutorial per se about the concepts of building a blockchain from scratch

@Alinawaz-786
Copy link

Alinawaz-786 commented Nov 7, 2023

@LordGhostX How would I get save data from blockchain. when I try to use this fmt.Println(blockchain.blockData) I will get error in our terminal.
image
image

@gaby
Copy link

gaby commented Jan 9, 2024

@Alinawaz-786 You need to add methods for that. For example you can use the following:

// Method to get data of a single block by index
func (bc Blockchain) GetBlockData(index int) (map[string]interface{}, error) {
	if index < 0 || index >= len(bc.chain) {
		return nil, fmt.Errorf("index out of range")
	}
	return bc.chain[index].data, nil
}

// Method to get data of all blocks
func (bc Blockchain) GetAllBlockData() []map[string]interface{} {
	var allData []map[string]interface{}
	for _, block := range bc.chain {
		allData = append(allData, block.data)
	}
	return allData
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment