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
  • 相关阅读:
    医院产品演变畅想
    2014-1-19
    更新一下blog
    tostring的自动调用
    解决evernote更新报错问题
    健身日记
    跑步计划
    [转载]offsetHeight , clientHeight, scrollHeight 区别
    做一个院友网站杂记
    查好友摇一摇功能的感受
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12339699.html
Copyright © 2011-2022 走看看