通过http实现RPC命令的调用 实现添加块
查询当前所有块的信息* B6 d% V: \( E3 i y
: X: a0 Y# l* F# {( `
这里只做了两个命令 分别是get和write
源代码如下
基础功能的实现* q' z/ X( T" x* w- ?% H
4 v. u& N0 Z: a0 L _" @
package core
import (/ ]1 |9 y% S1 c# f# E1 U
"crypto/sha256"
"encoding/hex"
"time"
)
//定义区块
type Block struct {. s/ N6 s0 c; y# r$ a8 M( v# w
Index int64 //区块编号' j n* `+ L- n0 i
- Timestamp int64 //区块时间戳 R: j& B: P9 h9 s! M7 l8 i& c: \
- PrevBlockHash string //上一个区块的hash值
- Hash string //当前区块哈希值
- Data string //区块数据
- }
- //计算Hash) S' c M& F* _2 h
- func calculateHash(b *Block) string {6 p2 ]5 \2 A2 O- {. {! H; d/ C
- blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlockHash
- hashInBytes := sha256.Sum256([]byte(blockData)); _5 ^0 @0 x+ H- A- g7 e+ y' Y0 q1 J! h
- return hex.EncodeToString(hashInBytes[:]). G0 _: r0 d2 U3 h: c7 X, k! m8 U
- }
//生成新的区块* W, j4 E8 ~4 X& j) Z
func GenerateNewBlock(preBlock *Block, data string) *Block {
newBlock := &Block{}
newBlock.Index = preBlock.Index + 1
newBlock.PrevBlockHash = preBlock.Hash: L" k! _8 `( b& h
newBlock.Timestamp = time.Now().Unix()% |' z$ u8 w; [% @4 U
newBlock.Hash = calculateHash(newBlock)
newBlock.Data = data2 Q4 _6 H% m, i. B, \
return newBlock% ~" q( q8 F: z
}* u6 t9 b1 c6 t" I! N
//生成创始区块0 N# j7 y! R1 e, w
func GenerateGenesisBlock() *Block {3 Y, V( |* Q5 u$ K9 O) M
preBlock := &Block{}
preBlock.Index = -1
preBlock.Hash = ""
return GenerateNewBlock(preBlock, "Genesis Block")
}
将基础功能实现的块进行链接 实现blockchain
package core: T# m9 j& n& @+ G) u- |7 T" O
- `+ w* l' B7 L, ~2 {+ R
import (6 G# ?& g& G# C" n4 c7 R
"fmt"
"log"$ [+ w4 v7 B9 e0 @4 C9 c
)$ A1 \0 |0 t4 R# i% p, t
8 g9 J6 Z9 u: d1 Z2 ]
//定义区块链
type BlockChain struct {
Blocks []*Block
}
9 P5 w) G( q1 X* H2 o2 L& Q
//创建一个区块链6 V! Y% A; D9 e1 D1 y
func NewBlockChain() *BlockChain {
genesisBlock := GenerateGenesisBlock()
blockChain := &BlockChain{}2 X5 Z( e4 ?! ?
blockChain.AppendBlock(genesisBlock)
return blockChain
}+ G$ S/ Y2 Z* `2 E( H
6 K$ }6 Z6 J& g; B) c
//记录区块数据7 {. t, a z- W! ]2 g
func (bc *BlockChain) SendData(data string) {1 h# X1 u6 r2 }( k3 j& r
preBlock := bc.Blocks[len(bc.Blocks)-1]. d- U! W6 Y" L! W: L5 X4 o
newBlock := GenerateNewBlock(preBlock, data)
bc.AppendBlock(newBlock)- j" y9 M9 G* m4 g
}
//往区块链添加区块
func (bc *BlockChain) AppendBlock(newBlock *Block) {- l( _) x. q, }8 b+ ^4 P" Z
if len(bc.Blocks) == 0 {: X( Y! A5 X# @% |
bc.Blocks = append(bc.Blocks, newBlock)9 k$ g5 W! ]( w
return: N- [' R$ U/ M# k! Q
}
if isValid(newBlock, bc.Blocks[len(bc.Blocks)-1]) {
bc.Blocks = append(bc.Blocks, newBlock)6 ~* E' X; @9 K0 Q% q: ?
} else {
log.Fatal("invalid block"); s! A8 R2 Z `4 h8 b+ K9 A1 D$ N% b+ z
}- q1 H5 ^5 q8 w% a: o; P
return
}- o! H$ Z, Y9 P1 M- D( {8 ]
2 g: v/ X- ]% a1 M' S
//输出区块链信息
func (bc *BlockChain) Print() {# O& R. `, e1 w# p( z! p
for _, block := range bc.Blocks {
fmt.Printf("Index : %d\n", block.Index)0 K3 E, g: a) `+ x
fmt.Printf("Prev.Hash : %s\n", block.PrevBlockHash). @! A) L) C4 E$ S
fmt.Printf("Curr.Hash : %s\n", block.Hash)
fmt.Printf("Curr.Data : %s\n", block.Data)! @( ]2 Y2 a0 p
fmt.Printf("Curr.Timestamp : %d\n", block.Timestamp)
fmt.Println("==========================================")6 z4 ^- c e7 M: m; y
}) h/ [* @- y5 e! i
}2 G& ]% H+ M# g: {* a4 g) a/ G3 c
2 v* R2 C# J/ a
//验证区块& H& ~# C7 _4 u7 u4 [* v
func isValid(newBlock *Block, oldBlock *Block) bool {
if newBlock.Index-1 != oldBlock.Index {7 s9 q7 [$ |6 F$ ]/ p6 V2 N
return false) k6 Q) k) ^% m$ c
}6 I. }0 c, h9 s# D1 j/ V3 L
if newBlock.PrevBlockHash != oldBlock.Hash {
return false& w9 C) T0 R9 s/ z' l, P+ ~
}) L2 n- Z% b4 Y% \$ n8 h
if calculateHash(newBlock) != newBlock.Hash {2 W9 b' X8 @( w5 V2 m
return false& I: {! o- K; ?% K3 r7 M
}7 ~2 ?6 y& _9 l3 D
return true
}/ J+ o3 q1 A' u4 N% S7 a/ Z
实现RPC接口的交互
- package main! X/ N/ z7 \. F' W. `5 w6 d+ ~0 x
-
- import (9 j* r- k+ v) E. X( u
- "encoding/json"
- "BlockChain/core" }9 L c* Y5 @
- "io"
- "net/http"8 J) n/ g* u4 ^& E8 R9 B" D# }5 A% F
- )
- 7 V% ?( l. E8 F2 N7 l) }; Q' ~( I
- var blockChain *core.BlockChain
- 7 ] c' n( I, L
- func run() {
- http.HandleFunc("/block_chain/get", blockChainGetHandle)
- http.HandleFunc("/block_chain/write", blockChainWriteHandle). I" K- C; R7 q3 c6 d1 G
- http.ListenAndServe(":8332", nil)
- }; j% R2 \2 g* v* @" f' v# C3 }
- 7 l ~2 w L1 |" ]% f; Q1 R0 D
- func blockChainGetHandle(w http.ResponseWriter, r *http.Request) {
- bytes, err := json.Marshal(blockChain)
- if err != nil {% N! v; f8 S+ L3 Y1 n# h& H; ~
- http.Error(w, err.Error(), http.StatusInternalServerError)( E7 s0 J& i# P0 [" @; F" t
- return% q+ M' N# m" f
- }
- io.WriteString(w, string(bytes))4 N/ p' n. g' n4 B1 O( F6 s
- }9 H4 a) e/ S2 i3 J' x4 I/ l( M. ]9 H
-
- func blockChainWriteHandle(w http.ResponseWriter, r *http.Request) {, m8 ^: N2 o% u( o* I0 ?, a/ D
- blockData := r.URL.Query().Get("data"). v$ A( X$ g& p% Y% Z
- blockChain.SendData(blockData)2 h% n) |4 ^0 r* {
- blockChainGetHandle(w, r): D+ A6 ]3 v. n9 o* m' `" R1 E
- }& ~9 Q: d" w) m5 N, ]7 `1 w
- % B6 ~/ I( `4 i4 Y; r1 R% d6 b
- func main() {$ m) m f' i% ^7 |/ N$ w
- blockChain = core.NewBlockChain()
- run()
- }
通过两部分代码实现简易区块链的RPC调用