区块(生成创世区块、生成新区块)
package block
import (
"crypto/sha256"
"encoding/hex"
"math/rand"
"strconv"
"strings"
"time"
)
const Diff =3
type Block struct {
Index int
PreHash string
HashCode string
TimeStamp int
Diff int
Data string
Nonce int
}
func GenerateHashCode(block Block)string{
hashData:=strconv.Itoa(block.Nonce)+strconv.Itoa(block.Diff)+strconv.Itoa(block.Index)+block.PreHash
h:=sha256.New()
h.Write([]byte(hashData))
restmp := h.Sum(nil)
res := hex.EncodeToString(restmp)
return res
}
func CreateFirstBlock(data string)(firstBlock Block){
firstBlock.PreHash="0"
firstBlock.TimeStamp=int(time.Now().Unix())
firstBlock.Diff=Diff
firstBlock.Data=data
firstBlock.Index=0
firstBlock.Nonce=123
firstBlock.HashCode=GenerateHashCode(firstBlock)
return
}
func Pow(block *Block)string{
for {
hashCode := GenerateHashCode(*block)
if strings.HasPrefix(hashCode,strings.Repeat("0",block.Diff)) {
return hashCode
}
rand.Seed(time.Now().Unix())
block.Nonce+=rand.Intn(100)
}
}
func CreatNewBlock(preBlock Block, data string)(newBlock Block){
newBlock.PreHash=preBlock.HashCode
newBlock.Data=data
newBlock.Index=preBlock.Index+1
newBlock.Diff=Diff
newBlock.Nonce=123
newBlock.TimeStamp=int(time.Now().Unix())
hash := Pow(&newBlock)
newBlock.HashCode=hash
return
}
链(生成节点,添加新节点)
package chain
import (
"blockChain/block"
)
type Node struct {
NextNode *Node
Data *block.Block
}
func CreateFirstNode(block *block.Block)*Node{
firstNode:=new(Node)
firstNode.NextNode=nil
firstNode.Data=block
return firstNode
}
func CheckBlock(data *block.Block,preNode *Node)bool{
if data.PreHash!=preNode.Data.HashCode {
return false
}
if data.Index!=preNode.Data.Index+1 {
return false
}
return true
}
func Add(data *block.Block,preNode *Node) *Node{
if CheckBlock(data,preNode){
nextNode:=new(Node)
nextNode.NextNode=nil
nextNode.Data=data
preNode.NextNode=nextNode
return nextNode
}
return nil
}
func ShowNodeList(node *Node)[]block.Block{
tmp:=node
list:=make([]block.Block,0)
for {
if tmp.NextNode==nil {
list=append(list,*tmp.Data)
break
}
list=append(list,*tmp.Data)
tmp=tmp.NextNode
}
return list
}
http接口
- 基于gorilla/mux包实现的http请求(格式话返回所有的区块链信息)
- GET请求实现查看所有的区块链信息;
- POST请求增加新节点;
- init生成创世区块并在后面追加节点
import (
"blockChain/block"
"blockChain/chain"
"encoding/json"
"flag"
"fmt"
"github.com/gorilla/mux"
"io/ioutil"
"log"
"net/http"
)
var (
hostname string
port int
firstNode *chain.Node
)
func init(){
flag.StringVar(&hostname,"hostname","127.0.0.1","service IP or hostname")
flag.IntVar(&port,"port",8001,"service listen port")
firstBlock := block.CreateFirstBlock("创世区块")
firstNode = chain.CreateFirstNode(&firstBlock)
}
func Run(){
flag.Parse()
address := fmt.Sprintf("%s:%v", hostname, port)
log.Println("REST service on",address)
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/blockChain/list",GetListHandle).Methods("GET")
router.HandleFunc("/blockChain/add",PostAddHandle).Methods("POST")
err := http.ListenAndServe(address, router)
if err != nil {
log.Println("service listen err:",err)
}
}
func GetListHandle(writer http.ResponseWriter, request *http.Request) {
list := chain.ShowNodeList(firstNode)
writer.Header().Set("Content-Type","application/json")
indent, err := json.MarshalIndent(list, "", "\t")
if err != nil {
writer.WriteHeader(http.StatusNotFound)
writer.Write([]byte("not found"))
log.Println("json.MarshalIndent",err)
return
}
writer.WriteHeader(http.StatusOK)
writer.Write(indent)
}
func PostAddHandle(writer http.ResponseWriter, request *http.Request) {
bytes, err := ioutil.ReadAll(request.Body)
if err != nil {
log.Panic("ioutil.readall:",err)
}
defer request.Body.Close()
var req map[string]interface{}
err = json.Unmarshal(bytes, &req)
if err != nil {
log.Panic("json.Unmarshal failed;err:",err)
}
data:=req["data"].(string)
pre:=firstNode
for pre.NextNode!=nil{
pre=pre.NextNode
}
newBlock := block.CreatNewBlock(*pre.Data, data)
newnode := chain.Add(&newBlock, pre)
list := chain.ShowNodeList(firstNode)
rep:=make(map[string]interface{})
if newnode == nil {
rep["status"]="add failed!!!"
log.Println("Add new node failed")
}
log.Println("Add new node success")
rep["status"]="add success!!!"
rep["result"]=list
writer.Header().Set("content-Type","application/json")
indent, err:= json.MarshalIndent(rep, "", "\t")
if err != nil {
writer.WriteHeader(http.StatusNotFound)
writer.Write([]byte("not found!!!"))
}
writer.WriteHeader(http.StatusOK)
writer.Write(indent)
}
func main(){
service.Run()
}
//服务端
D:\www\Blockchain_go\pow>go run main.go
2020/07/05 22:41:53 REST service on 127.0.0.1:8001
2020/07/05 22:42:20 Add new node success
2020/07/05 22:43:00 Add new node success
//客户端
D:\www\Blockchain_go\pow>curl -X GET http://localhost:8001/blockChain/list
[
{
"Index": 0,
"PreHash": "0",
"HashCode": "38fc3af258669791206922284800c53a0eab92b0d602253e447a71b802f5c77f",
"TimeStamp": 1593960113,
"Diff": 3,
"Data": "创世区块",
"Nonce": 123
},
{
"Index": 1,
"PreHash": "38fc3af258669791206922284800c53a0eab92b0d602253e447a71b802f5c77f",
"HashCode": "0001bed84d1c2c3a2913f067865824effe66d20152eff783af17b532b2fe577d",
"TimeStamp": 1593960140,
"Diff": 3,
"Data": "second node",
"Nonce": 132996
},
{
"Index": 2,
"PreHash": "0001bed84d1c2c3a2913f067865824effe66d20152eff783af17b532b2fe577d",
"HashCode": "0001f89dc9b82c524c0e3e0c36fd56749c97ddc7fb2b1c2d3bb5baeca1142698",
"TimeStamp": 1593960180,
"Diff": 3,
"Data": "third node",
"Nonce": 105283
}
]
D:\www\Blockchain_go\pow>curl -X POST -d "{\"data\":\"third node\"}" http://localhost:8001/blockChain/add
{
"result": [
{
"Index": 0,
"PreHash": "0",
"HashCode": "38fc3af258669791206922284800c53a0eab92b0d602253e447a71b802f5c77f",
"TimeStamp": 1593960113,
"Diff": 3,
"Data": "创世区块",
"Nonce": 123
},
{
"Index": 1,
"PreHash": "38fc3af258669791206922284800c53a0eab92b0d602253e447a71b802f5c77f",
"HashCode": "0001bed84d1c2c3a2913f067865824effe66d20152eff783af17b532b2fe577d",
"TimeStamp": 1593960140,
"Diff": 3,
"Data": "second node",
"Nonce": 132996
},
{
"Index": 2,
"PreHash": "0001bed84d1c2c3a2913f067865824effe66d20152eff783af17b532b2fe577d",
"HashCode": "0001f89dc9b82c524c0e3e0c36fd56749c97ddc7fb2b1c2d3bb5baeca1142698",
"TimeStamp": 1593960180,
"Diff": 3,
"Data": "third node",
"Nonce": 105283
}
],
"status": "add success!!!"
}