zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Openstack API 开发 快速入门
    virtualBox虚拟机到vmware虚拟机转换
    使用Blogilo 发布博客到cnblogs
    Openstack Troubleshooting
    hdoj 1051 Wooden Sticks(上升子序列个数问题)
    sdut 2430 pillars (dp)
    hdoj 1058 Humble Numbers(dp)
    uva 10815 Andy's First Dictionary(快排、字符串)
    sdut 2317 Homogeneous squares
    hdoj 1025 Constructing Roads In JGShining's Kingdom(最长上升子序列+二分)
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12339699.html
Copyright © 2011-2022 走看看