-
-
Save LordGhostX/bb92b907731ee8ebe465a28c5c431cb4 to your computer and use it in GitHub Desktop.
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()) | |
} |
Awesome, thanks!
I have hesitation learning Go since I am comfortable with PHP and Node. This is a nice intro though. Thanks
@LordGhostX Any recommended tutorial?
Great to learn the basics of blockchain while improving in Go! Thanks.
@LordGhostX How would I read the data of a block? Would I just do fmt.Println(blockchain.blockData)
?
@ekpono gobyexample.com is a very good resource. Also, learnxinyminutes if you're a speed learner.
@LordGhostX how do i learn the concepts taught in this tutorial per se about the concepts of building a blockchain from scratch
@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.
@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
}
No it is not, feel free to use it as you wish.