はじめに
前回は、transactionsの実装までやりましたが、今回はnonceの実装をしていきます。
- 前回までの記事
- バージョン
- Go 1.22.0
nonceとは
nonceは、新しいブロックを作成する時に、そのブロックが正しいものだと証明するために使われます。
下の図のように新しいブロックを作成する時に、challenge、prev hashとtransactionsを使用してハッシュを生成します。このときchallengeはnonceに入れる候補となる値です。
例えば下の図では、生成したハッシュの先頭が000となるまでchallengeを増やしていって、challengeが10の時ハッシュの先頭が000になったので、challengeの値である10をnonceに入れてブロックを作成します。
今回は、先頭3文字が0になるまで計算する実装にしています。この先頭何文字までが0になるまで計算するかの値をdifficultyと呼び、実際はもっと大きな値が設定されます。
実装
イメージ図
下の図のnonceの実装をしていきます。
nonceの実装
まず、nonceの実装をしていきます。
const MINING_DIFFICULTY = 3
func (bc *Blockchain) CopyTransactionPool() []*Transaction {
transactions := make([]*Transaction, 0)
for _, t := range bc.transactionPool {
transactions = append(transactions,
NewTransaction(t.senderBlockchainAddress,
t.recipientBlockchainAddress,
t.value))
}
return transactions
}
func (bc *Blockchain) ValidProof(nonce int, previousHash [32]byte, transactions []*Transaction, difficulty int) bool {
zeros := strings.Repeat("0", difficulty)
guessBlock := Block{0, nonce, previousHash, transactions}
guessHashStr := fmt.Sprintf("%x", guessBlock.Hash())
return guessHashStr[:difficulty] == zeros
}
func (bc *Blockchain) ProofOfWork() int {
transactions := bc.CopyTransactionPool()
previousHash := bc.LastBlock().Hash()
nonce := 0
for !bc.ValidProof(nonce, previousHash, transactions, MINING_DIFFICULTY) {
nonce += 1
}
return nonce
}
今回は、difficultyを3として実装するので、MINING_DIFFICULTY=3で定数を定義します。
CopyTransactionPoolでは、Poolにあるtransactionsをコピーしています。
ValidProofでは、引数で受け取ったnonceとpreviousHashとtransactionsを使ってハッシュを生成し、そのハッシュが有効なものか(今回の実装では、生成されたハッシュの先頭3文字が000であるとき有効)を求めています。
ProofOfWorkでは、nonceを1ずつ増やしながら、ValidProofをループさせて実行して、解答となるnonceを求めています。
おわりに
今回は、nonceの実装をしていきました。
次回は、マイニングの実装をしていきます。
次の記事
参考