1. 程式人生 > >使用go語言編寫簡易Blockchain實現web呼叫RPC過程

使用go語言編寫簡易Blockchain實現web呼叫RPC過程

在本機埠進行查詢 由於是第一次執行該鏈 生成創世區塊

通過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呼叫