Skip to content

实践部分

创建Block

package core

import (
    "crypto/sha256"
    "encoding/hex"
    "time"
)

type Block struct {
    // 区块头
    Index         int64  // 区块编号
    Timestamp     int64  // 区块时间戳
    PrevBlockHash string // 上一个区块hash值
    Hash          string // 当前区块hash值

    // 区块体
    Data string // 区块数据
}

// 创建hash值
func caculateHash(b Block) string {
    blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlockHash
    hashInBytes := sha256.Sum256([]byte(blockData))
    return hex.EncodeToString(hashInBytes[:])
}

// 创建新的区块
func GenerateNewBlock(preBlock Block, data string) Block {
    newBlock := Block{}
    newBlock.Index = preBlock.Index + 1
    newBlock.PrevBlockHash = preBlock.Hash
    newBlock.Timestamp = time.Now().Unix()
    newBlock.Data = data
    newBlock.Hash = caculateHash(newBlock)
    return newBlock
}

// 创世区块
func GenerateGenesisBlock() Block {
    preBlock := Block{}
    preBlock.Index = -1
    preBlock.Hash = ""
    return GenerateNewBlock(preBlock, "Genesis Block")
}

创建Blockchain

package core

import (
    "fmt"
    "log"
)

type Blockchain struct {
    Blocks []*Block
}

func NewBlockChain() *Blockchain {
    genesisBlock := GenerateGenesisBlock()
    blockchain := Blockchain{}
    blockchain.ApendBlock(&genesisBlock)
    return &blockchain
}

func (bc *Blockchain) SendData(data string) {
    preBlock := bc.Blocks[len(bc.Blocks)-1]
    newBlock := GenerateNewBlock(*preBlock, data)
    bc.ApendBlock(&newBlock)
}

func (bc *Blockchain) ApendBlock(newBlock *Block) {
    if len(bc.Blocks) == 0 {
        bc.Blocks = append(bc.Blocks, newBlock)
        return
    }
    if isValid(*newBlock, *bc.Blocks[len(bc.Blocks)-1]) {
        bc.Blocks = append(bc.Blocks, newBlock)
    } else {
        log.Fatal("invalid block")
    }
}

func (bc *Blockchain) Print() {
    for _, Block := range bc.Blocks {
        fmt.Printf("Index: %d\n", Block.Index)
        fmt.Printf("PrevHash: %s\n", Block.PrevBlockHash)
        fmt.Printf("CurrHash: %s\n", Block.Hash)
        fmt.Printf("Data: %s\n", Block.Data)
        fmt.Printf("Timestamp: %d\n", Block.Timestamp)
        fmt.Println()
    }
}

func isValid(newBlock Block, oldBlock Block) bool {
    if newBlock.Index-1 != oldBlock.Index {
        return false
    }
    if newBlock.PrevBlockHash != oldBlock.Hash {
        return false
    }
    if caculateHash(newBlock) != newBlock.Hash {
        return false
    }
    return true
}

创建main文件

package main

import "demochain/core"

func main() {
    bc := core.NewBlockChain()
    bc.SendData("Send 1 BTC to Jartin")
    bc.SendData("Send 1 EOS to Jartin")
    bc.Print()
}


// 输出
MacintoshdeMacBook-Pro-139:cmd elasticnotes$ go run main.go 
Index: 0
PrevHash: 
CurrHash: 0d8845eb2da42f75aef4ee920f644975d73347e0331d17b37209c4f32ef4867f
Data: Genesis Block
Timestamp: 1677140165

Index: 1
PrevHash: 0d8845eb2da42f75aef4ee920f644975d73347e0331d17b37209c4f32ef4867f
CurrHash: b11305449703848e79f02f0ba7f7db6bdd085a4a5ea50382ea4cca77644c376b
Data: Send 1 BTC to Jartin
Timestamp: 1677140165

Index: 2
PrevHash: b11305449703848e79f02f0ba7f7db6bdd085a4a5ea50382ea4cca77644c376b
CurrHash: 751c3793ee3492f5e050c6b662f4d832bc125dde0aae813147e5459abc23f29a
Data: Send 1 EOS to Jartin
Timestamp: 1677140165

创建Http Server

package main

import (
    "demochain/core"
    "encoding/json"
    "io"
    "net/http"
)

var blockchain *core.Blockchain

func run() {
    http.HandleFunc("/blockchain/get", blockchainGetHandler)
    http.HandleFunc("/blockchain/write", blockchainWriteHandler)
    http.ListenAndServe("localhost:8888", nil)
}

func blockchainGetHandler(w http.ResponseWriter, r *http.Request) {
    bytes, err := json.Marshal(blockchain)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    io.WriteString(w, string(bytes))
}

func blockchainWriteHandler(w http.ResponseWriter, r *http.Request) {
    blockData := r.URL.Query().Get("data")
    blockchain.SendData(blockData)
    blockchainGetHandler(w, r)
}

func main() {
    blockchain = core.NewBlockChain()
    run()
}

完整代码示例

  • 目录层级
    MacintoshdeMacBook-Pro-139:demochain elasticnotes$ tree -L 3
    .
    ├── cmd
       └── main.go
    ├── core
       ├── Block.go
       └── Blockchain.go
    ├── go.mod
    └── rpc
        └── Server.go
    
    3 directories, 5 files
    
  • 代码

    package main
    
    import "demochain/core"
    
    func main() {
        bc := core.NewBlockChain()
        bc.SendData("Send 1 BTC to Jartin")
        bc.SendData("Send 1 EOS to Jartin")
        bc.Print()
    }
    
    package core
    
    import (
        "crypto/sha256"
        "encoding/hex"
        "time"
    )
    
    type Block struct {
        // 区块头
        Index         int64  // 区块编号
        Timestamp     int64  // 区块时间戳
        PrevBlockHash string // 上一个区块hash值
        Hash          string // 当前区块hash值
    
        // 区块体
        Data string // 区块数据
    }
    
    // 创建hash值
    func caculateHash(b Block) string {
        blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlockHash
        hashInBytes := sha256.Sum256([]byte(blockData))
        return hex.EncodeToString(hashInBytes[:])
    }
    
    // 创建新的区块
    func GenerateNewBlock(preBlock Block, data string) Block {
        newBlock := Block{}
        newBlock.Index = preBlock.Index + 1
        newBlock.PrevBlockHash = preBlock.Hash
        newBlock.Timestamp = time.Now().Unix()
        newBlock.Data = data
        newBlock.Hash = caculateHash(newBlock)
        return newBlock
    }
    
    // 创世区块
    func GenerateGenesisBlock() Block {
        preBlock := Block{}
        preBlock.Index = -1
        preBlock.Hash = ""
        return GenerateNewBlock(preBlock, "Genesis Block")
    }
    
    package core
    
    import (
        "fmt"
        "log"
    )
    
    type Blockchain struct {
        Blocks []*Block
    }
    
    func NewBlockChain() *Blockchain {
        genesisBlock := GenerateGenesisBlock()
        blockchain := Blockchain{}
        blockchain.ApendBlock(&genesisBlock)
        return &blockchain
    }
    
    func (bc *Blockchain) SendData(data string) {
        preBlock := bc.Blocks[len(bc.Blocks)-1]
        newBlock := GenerateNewBlock(*preBlock, data)
        bc.ApendBlock(&newBlock)
    }
    
    func (bc *Blockchain) ApendBlock(newBlock *Block) {
        if len(bc.Blocks) == 0 {
            bc.Blocks = append(bc.Blocks, newBlock)
            return
        }
        if isValid(*newBlock, *bc.Blocks[len(bc.Blocks)-1]) {
            bc.Blocks = append(bc.Blocks, newBlock)
        } else {
            log.Fatal("invalid block")
        }
    }
    
    func (bc *Blockchain) Print() {
        for _, Block := range bc.Blocks {
            fmt.Printf("Index: %d\n", Block.Index)
            fmt.Printf("PrevHash: %s\n", Block.PrevBlockHash)
            fmt.Printf("CurrHash: %s\n", Block.Hash)
            fmt.Printf("Data: %s\n", Block.Data)
            fmt.Printf("Timestamp: %d\n", Block.Timestamp)
            fmt.Println()
        }
    }
    
    func isValid(newBlock Block, oldBlock Block) bool {
        if newBlock.Index-1 != oldBlock.Index {
            return false
        }
        if newBlock.PrevBlockHash != oldBlock.Hash {
            return false
        }
        if caculateHash(newBlock) != newBlock.Hash {
            return false
        }
        return true
    }
    
    package main
    
    import (
        "demochain/core"
        "encoding/json"
        "io"
        "net/http"
    )
    
    var blockchain *core.Blockchain
    
    func run() {
        http.HandleFunc("/blockchain/get", blockchainGetHandler)
        http.HandleFunc("/blockchain/write", blockchainWriteHandler)
        http.ListenAndServe("localhost:8888", nil)
    }
    
    func blockchainGetHandler(w http.ResponseWriter, r *http.Request) {
        bytes, err := json.Marshal(blockchain)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        io.WriteString(w, string(bytes))
    }
    
    func blockchainWriteHandler(w http.ResponseWriter, r *http.Request) {
        blockData := r.URL.Query().Get("data")
        blockchain.SendData(blockData)
        blockchainGetHandler(w, r)
    }
    
    func main() {
        blockchain = core.NewBlockChain()
        run()
    }
    
  • 启动 访问结果

    MacintoshdeMacBook-Pro-139:rpc elasticnotes$ go run Server.go 
    

    http://localhost:8888/blockchain/get
    {
        "Blocks": [
            {
                "Index": 0,
                "Timestamp": 1677141979,
                "PrevBlockHash": "",
                "Hash": "0d8845eb2da42f75aef4ee920f644975d73347e0331d17b37209c4f32ef4867f",
                "Data": "Genesis Block"
            }
        ]
    }
    
    http://localhost:8888/blockchain/write?data=Send%202%20BTC%20to%20Jartin
    {
        "Blocks": [
            {
                "Index": 0,
                "Timestamp": 1677141979,
                "PrevBlockHash": "",
                "Hash": "0d8845eb2da42f75aef4ee920f644975d73347e0331d17b37209c4f32ef4867f",
                "Data": "Genesis Block"
            },
            {
                "Index": 1,
                "Timestamp": 1677142099,
                "PrevBlockHash": "0d8845eb2da42f75aef4ee920f644975d73347e0331d17b37209c4f32ef4867f",
                "Hash": "b11305449703848e79f02f0ba7f7db6bdd085a4a5ea50382ea4cca77644c376b",
                "Data": "Send 1 BTC to Jartin"
            },
            {
                "Index": 2,
                "Timestamp": 1677142109,
                "PrevBlockHash": "b11305449703848e79f02f0ba7f7db6bdd085a4a5ea50382ea4cca77644c376b",
                "Hash": "751c3793ee3492f5e050c6b662f4d832bc125dde0aae813147e5459abc23f29a",
                "Data": "Send 2 BTC to Jartin"
            }
        ]
    }