使用go語言編寫簡易Blockchain實現web呼叫RPC過程
阿新 • • 發佈:2018-12-20
在本機埠進行查詢 由於是第一次執行該鏈 生成創世區塊
通過http實現RPC命令的呼叫 實現新增塊
查詢當前所有塊的資訊
這裡只做了兩個命令 分別是get和write
原始碼如下
基礎功能的實現
package core import ( "crypto/sha256" "encoding/hex" "time" ) //定義區塊 type Block struct { Index int64 //區塊編號 Timestamp int64 //區塊時間戳 PrevBlockHash string //上一個區塊的hash值 Hash string //當前區塊雜湊值 Data string //區塊資料 } //計算Hash func calculateHash(b *Block) string { blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlockHash 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.Hash = calculateHash(newBlock) newBlock.Data = data return newBlock } //生成創始區塊 func GenerateGenesisBlock() *Block { preBlock := &Block{} preBlock.Index = -1 preBlock.Hash = "" return GenerateNewBlock(preBlock, "Genesis Block") }
將基礎功能實現的塊進行連結 實現blockchain
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") } return } //輸出區塊鏈資訊 func (bc *BlockChain) Print() { for _, block := range bc.Blocks { fmt.Printf("Index : %d\n", block.Index) fmt.Printf("Prev.Hash : %s\n", block.PrevBlockHash) fmt.Printf("Curr.Hash : %s\n", block.Hash) fmt.Printf("Curr.Data : %s\n", block.Data) fmt.Printf("Curr.Timestamp : %d\n", block.Timestamp) fmt.Println("==========================================") } } //驗證區塊 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 }
實現RPC介面的互動
package main import ( "encoding/json" "BlockChain/core" "io" "net/http" ) var blockChain *core.BlockChain func run() { http.HandleFunc("/block_chain/get", blockChainGetHandle) http.HandleFunc("/block_chain/write", blockChainWriteHandle) http.ListenAndServe(":8332", nil) } func blockChainGetHandle(w http.ResponseWriter, r *http.Request) { bytes, err := json.Marshal(blockChain) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } io.WriteString(w, string(bytes)) } func blockChainWriteHandle(w http.ResponseWriter, r *http.Request) { blockData := r.URL.Query().Get("data") blockChain.SendData(blockData) blockChainGetHandle(w, r) } func main() { blockChain = core.NewBlockChain() run() }
通過兩部分程式碼實現簡易區塊鏈的RPC呼叫