프로젝트 구조
block.go
package core
import (
"crypto/sha256"
"encoding/hex"
"time"
)
type Block struct {
Index int64
Timestamp int64
PrevBlockHash string
Hash string
Data string
}
func calculateHash(b Block) string {
blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlockHash + b.Data
hashInBytes := sha256.Sum256([]byte(blockData))
return hex.EncodeToString(hashInBytes[:])
}
func GenerateNewBlock(preBlock Block, data string) Block {
newBlock := Block{
}
newBlock.Index = preBlock.Index + 1
newBlock.PrevBlockHash = preBlock.Hash
newBlock.Timestamp = time.Now().Unix()
newBlock.Data = data
newBlock.Hash = calculateHash(newBlock)
return newBlock
}
func GenerateGenesisBlock() Block {
preBlock := Block{
}
preBlock.Index = -1
preBlock.Hash = ""
return GenerateNewBlock(preBlock, "Genesis Block")
}
blockchain.go
package core
import (
"fmt"
"log"
)
type Blockchain struct {
Blocks []*Block
}
func NewBlockchain() *Blockchain {
genesisBlock := GenerateGenesisBlock()
blockchain := Blockchain{
}
blockchain.AppendBlock(&genesisBlock)
return &blockchain
}
func (bc *Blockchain) SendData(data string) {
preBlock := bc.Blocks[len(bc.Blocks)-1]
newBlock := GenerateNewBlock(*preBlock, data)
bc.AppendBlock(&newBlock)
}
func (bc *Blockchain) AppendBlock(newBlock *Block) {
if len(bc.Blocks) == 0 {
bc.Blocks = append(bc.Blocks, newBlock)
return
}
if isValid(*newBlock, *bc.Blocks[len(bc.Blocks)-1]) {
bc.Blocks = append(bc.Blocks, newBlock)
} else {
log.Fatal("invalid block")
}
}
func (bc *Blockchain) Print() {
for _, block := range bc.Blocks {
fmt.Printf("Index: %d\n", block.Index)
fmt.Printf("PrevHash: %s\n", block.PrevBlockHash)
fmt.Printf("CurrHash: %s\n", block.Hash)
fmt.Printf("Data: %s\n", block.Data)
fmt.Printf("Timestamp: %d\n", block.Timestamp)
}
}
func isValid(newBlock Block, oldBlock Block) bool {
if newBlock.Index-1 != oldBlock.Index {
return false
}
if newBlock.PrevBlockHash != oldBlock.Hash {
return false
}
if calculateHash(newBlock) != newBlock.Hash {
return false
}
return true
}
server.go는 간단한 호출을 위해 인터페이스를 캡슐화합니다.
package main
import (
"encoding/json"
"go-blockchain/core"
"io"
"net/http"
)
var blockchain *core.Blockchain
func run() {
http.HandleFunc("/blockchain/get", blockchainGetHandler)
http.HandleFunc("/blockchain/write", blockchainWriteHandler)
http.ListenAndServe("localhost:8080", nil)
}
func blockchainGetHandler(w http.ResponseWriter, r *http.Request) {
bytes, error := json.Marshal(blockchain)
if error != nil {
http.Error(w, error.Error(), http.StatusInternalServerError)
return
}
io.WriteString(w, string(bytes))
}
func blockchainWriteHandler(w http.ResponseWriter, r *http.Request) {
blockData := r.URL.Query().Get("data")
blockchain.SendData(blockData)
blockchainGetHandler(w, r)
}
func main() {
blockchain = core.NewBlockchain()
run()
}
블록체인의 블록에 데이터 쓰기
http://localhost:8888/blockchain/write?data=Fabric 超级账本学习【9】基于Go语言自己动手实现区块链
블록체인의 블록 데이터 읽기
http://localhost:8888/blockchain/get