Go实现简易区块链

并不复杂

可以参考详细的解释

https://shusunny.github.io/sunnyblog/blockchain/simple-blockchain.html

package main

import (
    "crypto/md5"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "github.com/gorilla/mux"
    "io"
    "log"
    "net/http"
    "time"
)

type Block struct {
    Pos int
    Data BookCheckout
    Timestamp string
    Hash string
    PrevHash string
}

type BookCheckout struct {
    BookID string `json:"book_id"`
    User string `json:"user"`
    CheckoutDate string `json:"checkout_date"`
    IsGenesis bool `json:"is_genesis"`
}

type Book struct {
    ID string `json:"id"`
    Title string `json:"title"`
    Author string `json:"author"`
    PublishDate string `json:"publish_date"`
    ISBN string `json:"isbn"`
}

func (b *Block) generateHash() {
    bytes, _ := json.Marshal(b.Data)
    data := string(b.Pos) + b.Timestamp + string(bytes) + b.PrevHash
    hash := sha256.New()
    hash.Write([]byte(data))
    b.Hash = hex.EncodeToString(hash.Sum(nil))
}

func CreateBlock(prevBlock *Block, checkoutItem BookCheckout) *Block {
    block := &Block{}
    block.Pos = prevBlock.Pos + 1
    block.Timestamp = time.Now().String()
    block.Data = checkoutItem
    block.PrevHash = prevBlock.Hash
    block.generateHash()

    return block
}

type BlockChain struct {
    blocks []*Block
}

var Blockchain *BlockChain

func (bc *BlockChain) AddBlock(data BookCheckout) {
    prevBlock := bc.blocks[len(bc.blocks) - 1]
    block := CreateBlock(prevBlock, data)
    // todo validate
    if validBlock(block, prevBlock) {
        bc.blocks = append(bc.blocks, block)
    }

}

func GenesisBlock() *Block {
    return CreateBlock(&Block{}, BookCheckout{IsGenesis:true})
}

func NewBlockchain() *BlockChain {
    return &BlockChain{[]*Block{GenesisBlock()}}
}

func validBlock(block, prevBlock *Block) bool {
    if prevBlock.Hash != block.PrevHash {
        return false
    }
    if !block.validateHash(block.Hash) {
        return false
    }
    if prevBlock.Pos + 1 != block.Pos {
        return false
    }
    return true
}

func (b *Block) validateHash(hash string) bool {
    b.generateHash()
    if b.Hash != hash {
        return false
    }
    return true
}

func getBlockChain(w http.ResponseWriter, r *http.Request) {
    jbytes, err := json.MarshalIndent(Blockchain.blocks, "", "")
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        json.NewEncoder(w).Encode(err)
        return
    }
    io.WriteString(w, string(jbytes))
}

func writeBlock(w http.ResponseWriter, r *http.Request) {
    var checkoutItem BookCheckout
    if err := json.NewDecoder(r.Body).Decode(&checkoutItem); err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        log.Printf("could not write Block: %v", err)
        w.Write([]byte("could not write block"))
        return
    }
    Blockchain.AddBlock(checkoutItem)
    resp, err := json.MarshalIndent(checkoutItem, "", " ")
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        log.Printf("could not marshal payload: %v", err)
        w.Write([]byte("could not write block"))
        return
    }
    w.WriteHeader(http.StatusOK)
    w.Write(resp)
}

func newBook(w http.ResponseWriter, r *http.Request) {
    var book Book
    if err := json.NewDecoder(r.Body).Decode(&book); err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        log.Printf("could not create: %v", err)
        w.Write([]byte("could not create new Book"))
        return
    }
    h := md5.New()
    io.WriteString(h, book.ISBN + book.PublishDate)
    book.ID = fmt.Sprintf("%x", h.Sum(nil))
    resp, err := json.MarshalIndent(book, "", " ")
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        log.Printf("could not marshal payload: %v", err)
        w.Write([]byte("could not save book data"))
        return
    }
    w.WriteHeader(http.StatusOK)
    w.Write(resp)
}

func main() {
    Blockchain = NewBlockchain()

    r := mux.NewRouter()
    r.HandleFunc("/", getBlockChain).Methods("GET")
    r.HandleFunc("/", writeBlock).Methods("POST")
    r.HandleFunc("/new", newBook).Methods("POST")

    go func() {
        for _, block := range Blockchain.blocks {
            fmt.Printf("Prev.hash: %x
", block.PrevHash)
            bytes, _ := json.MarshalIndent(block.Data, "", " ")
            fmt.Printf("Data: %v
", string(bytes))
            fmt.Printf("Hash: %x
", block.Hash)
            fmt.Println()
        }
    }()

    log.Println("Listening on port 3000")

    log.Fatal(http.ListenAndServe(":3000", r))
}

end

一个没有高级趣味的人。 email:hushui502@gmail.com
原文地址:https://www.cnblogs.com/CherryTab/p/12339699.html