実践#Go言語に基づくブロックチェーンのDIY実装

0 紹介

学習目標: 1. ブロックチェーンとは何かを理解する; 2. ブロックチェーンの基本構造をマスターする; 3. ブロックチェーンの基本モデルを構築する;

  • 理論的部分: 1. ブロックチェーンの 7 層アーキテクチャ モデル; 2. ブロックチェーンのチェーン構造;
  • 実践的な部分: 1. ブロックを作成する; 2. ブロックの「チェーン」を作成する; 3. ブロックチェーンにアクセスする;

開発環境:GoLand(有料、学生は無料で申請可能、要証明)
ブロックチェーンの理論的基礎については、私が書いた他のブログを参考にしてください この記事では主に実践を紹介します。

オープン ソース コード: https://github.com/hexbo/go-blockchain-demo
お役に立ったら、星を付けて共有してください ~ pr について言及することも歓迎します


1 ブロックチェーンの理論的根拠




データレイヤー

ハッシュ

ハッシュ関数の特徴: 一方向性、確実性、隠蔽性、改ざん防止、衝突防止。

ブロックチェーンの最も基本的な技術はハッシュです. これは go で書かれたハッシュのデモです:

package main

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

func calcHash(toBeHashed string) string {
    
    
	hashInBytes := sha256.Sum256([]byte(toBeHashed))
	hashInStr := hex.EncodeToString(hashInBytes[:])
	log.Printf("%s %s", toBeHashed, hashInStr)
	return hashInStr
}

func main() {
    
    
	calcHash("test1")
}

Go に慣れていない場合は、上記のコードについて次のような疑問を抱くかもしれません。

2 ブロックチェーンモデルを 0 から 1 に実現する

コンポーネント: 1. ブロックとチェーン構造を実現する; 2. シンプルな HTTP サーバーを実現し、読み書きインターフェースを公開する;

注: Go 言語関数名の大文字と小文字: 小文字はメソッドが現在のパッケージでのみ使用でき、プライベート メソッドであることを意味し、大文字はパブリック メソッドを意味します。

ブロック ブロック

package core

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

type Block struct {
    
    
	Index         int64  // 区块编号
	Timestamp     int64  // 区块时间戳
	PrevBlockHash string // 上一个区块哈希值
	Hash          string // 当前区块哈希
	Data          string // 区块数据
}

func calculateHash(b Block) string {
    
    
	blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlockHash + b.Data
	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 = calculateHash(newBlock)
	return newBlock
}

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

チェーン構造

コードの説明: 関数の前のパラメーター名は構造体 functionの構文です。これは、GO で構造体にバインドされる C++ クラス メンバー関数に似ています。

package core

import (
	"fmt"
	"log"
)

type Blockchain struct {
    
    
	Blocks []*Block
}

func NewBlockchain() *Blockchain {
    
    
	genesisBlock := GenerateGenesisBlock()
	blockchain := Blockchain{
    
    }
	blockchain.AppendBlock(&genesisBlock)
	return &blockchain
}

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

func (bc *Blockchain) AppendBlock(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)
	}
}

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

[質問] 次のコード: ここの len 関数は冗長ではありませんか?
Cのstrlenはchar配列を1回トラバースする必要があるので、O(1)ではなくO(n)の複雑さに相当するGoのlen関数がわからない

if isValid(*newBlock, *bc.Blocks[len(bc.Blocks)-1]) {
    
    

説明: 上記の go 文字列ストレージに関する質問を参照してください. Go は、文字列ポインタの末尾の '\0' ではなく先頭に文字列長データを格納するため、O(1) クエリ可能である必要があります.

CMD 検証

package main

import "go-blockchain/core"

func main() {
    
    
	bc := core.NewBlockchain()
	bc.SendData("Send 1 BTC to Alice")
	bc.SendData("Send 1 EOS to Bob")
	bc.Print()
}

HTTP RPC 読み取りおよび書き込み

package main

import (
	"encoding/json"
	"go-blockchain/core"
	"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, error := json.Marshal(blockchain)
	if error != nil {
    
    
		http.Error(w, error.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()
}

実行後、localhost:8888/blockchain/get にアクセスして現在のブロック データを表示し、/write?data="xxxx" にアクセスしてデータを書き込みます。

参照

  1. ビデオ

おすすめ

転載: blog.csdn.net/qq_33583069/article/details/125923989