在本机端口进行查询 由于是第一次运行该链 生成创世区块
通过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调用