はじめに
前回は、ブロックチェーンについてまとめましたが、今回から実際にGo言語で実装していきます。
- 前回の記事
- バージョン
- Go 1.22.0
実装
イメージ図
下の図のようなイメージで実装していきます。
- prev hash
- 前のブロックの情報
- timestamp
- 生成の時間
- nonce
- nonceの計算結果
- transactions
- 取引履歴
- Pool
- 取引情報が入る
上の図から新しいブロックが作られたとき、下の図のようになり、新しいブロックのprev hashには前のブロックの情報が入ります。また、Poolに溜まっていた取引情報が新しいブロックのtransactionsに入り、Poolの中は空になります。
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の実装をしていきます。
次の記事
参考