1
0

Go言語でブロックチェーンのシステムを作成する(その2)

Last updated at Posted at 2024-03-31

はじめに

前回は、ブロックチェーンについてまとめましたが、今回から実際にGo言語で実装していきます。

  • 前回の記事

  • バージョン
    • Go 1.22.0

実装

イメージ図

下の図のようなイメージで実装していきます。

ブロックチェーン1.png
  • prev hash
    • 前のブロックの情報
  • timestamp
    • 生成の時間
  • nonce
    • nonceの計算結果
  • transactions
    • 取引履歴
  • Pool
    • 取引情報が入る

上の図から新しいブロックが作られたとき、下の図のようになり、新しいブロックのprev hashには前のブロックの情報が入ります。また、Poolに溜まっていた取引情報が新しいブロックのtransactionsに入り、Poolの中は空になります。

ブロックチェーン2.png

Blockの作成

まずは、Blockの作成をしていきます。

type Block struct {
	nonce        int
	previousHash [32]byte
	timestamp    int64
	transactions []string
}

func NewBlock(nonce int, previousHash [32]byte) *Block {
	b := new(Block)
	b.timestamp = time.Now().UnixNano()
	b.nonce = nonce
	b.previousHash = previousHash
	return b
}

Blockは、nonce、previousHash、timestamp、transactionsでstructを定義します。
NewBlockでは、nonceとpreviousHashを引数にとって、Blockを作成しています。

Blockchainの作成

次に、Blockchainの作成をしていきます。

type Blockchain struct {
	transactionPool []string
	chain           []*Block
}

func NewBlockchain() *Blockchain {
    b := &Block{}
	bc := new(Blockchain)
	bc.CreateBlock(0, b.Hash())
	return bc
}

func (bc *Blockchain) CreateBlock(nonce int, previousHash [32]byte) *Block {
	b := NewBlock(nonce, previousHash)
	bc.chain = append(bc.chain, b)
	return b
}

Blockchainは、transactionPool、chainでstructを定義します。
NewBlockchainでは、Blockchainを新しく作成し、CreateBlockを呼んで一番最初のBlockを作成して、Blockchainを返しています。CreateBlockを呼ぶときの引数には、前のBlockが存在していないので、とりあえずnonceに0、previousHashには空のBlockを作っておいて、そのBlockのハッシュを入れています。b.Hash()については後で実装します。
CreateBlockでは、Blockを作成した後、そのBlockのポインタをBlockchainのchainに入れています。

Blockのハッシュを実装

次に、Blockのハッシュを実装していきます。

func (b *Block) Hash() [32]byte {
	m, _ := json.Marshal(b)
	return sha256.Sum256([]byte(m))
}

func (b *Block) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Timestamp    int64    `json:"timestamp"`
		Nonce        int      `json:"nonce"`
		PreviousHash [32]byte `json:"previous_hash"`
		Transactions []string `json:"transactions"`
	}{
		Timestamp:    b.timestamp,
		Nonce:        b.nonce,
		PreviousHash: b.previousHash,
		Transactions: b.transactions,
	})
}

func (bc *Blockchain) LastBlock() *Block {
	return bc.chain[len(bc.chain)-1]
}

Hashでは、BlockをJSON形式に変換して、それをハッシュの文字列に変換しています。
Blockのstructのフィールド名が小文字から始まっていますが、フィールド名が小文字だとプライベートなフィールドとして認識されてしまい、うまくマッピングできていません。そこでMarshalJSONでは、大文字に変えてjson.Marshalをするようにしています。
LastBlockでは、previousHashに前のBlockのハッシュを入れたいので、どのBlockが最後のBlockかを返しています。

おわりに

今回は、Block、Blockchainの作成、hashの実装をしていきました。
次回は、transactionsの実装をしていきます。

次の記事

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0