在上次的学习中(区块链学习(1))我们已经学会了搭建一个非常简单的区块链,但是真的区块链中有一个核心思想:向区块链中添加一个新的区块时,需要先完成一些困难的工作,从而保证区块链的稳定和安全。
如果我想向区块链中添加一个新区块,有什么方法能证明我的工作已经足够了呢,这就会引入一个新的概念,即工作量证明。
以比特币为例,获得新的比特币(新增一个区块)的方法流程如下:
1. 取一些公开的数据;
2. 给这个公开数据添加一个计数器。计数器默认从 0 开始;
3. 将 data(数据) 和 counter(计数器) 组合到一起,获得一个哈希;
4. 若哈希符合一定条件则结束,不符合则重复3-4;
代码实现
以比特币为例,首先我们需要定义一个难度:
const targetBits = 24 // 目标哈希值前缀0的个数
这里进行前缀0验证的方式非常有趣,构造了一个符合前缀24个0的最小数,即(0000...100000....)将哈希值与这个数进行大小比较
type ProofOfWork struct {
block *Block
target *big.Int
}
func NewProofOfWork(b *Block) *ProofOfWork {
target := big.NewInt(1)
target.Lsh(target, uint(256-targetBits))
pow := &ProofOfWork{b, target}
return pow
}
下面是工作量证明的核心代码:
func (pow *ProofOfWork) Run() (int, []byte) {
var hashInt big.Int
var hash [32]byte
nonce := 0
fmt.Printf("Mining the block containing \"%s\"\n", pow.block.Data)
for nonce < maxNonce {
data := pow.prepareData(nonce)
hash = sha256.Sum256(data)
hashInt.SetBytes(hash[:])
if hashInt.Cmp(pow.target) == -1 {
fmt.Printf("\r%x", hash)
break
} else {
nonce++
}
}
fmt.Print("\n\n")
return nonce, hash[:]
}
nonce作为计数器其实可以作为新的区块的一个属性添加到Block结构体中:
type Block struct {
Timestamp int64
Data []byte
PrevBlockHash []byte
Hash []byte
Nonce int
}
我们离真正的区块链又进了一步:现在需要经过一些困难的工作才能加入新的块,因此挖矿就有可能了。但是,它仍然缺少一些至关重要的特性:区块链数据库并不是持久化的,没有钱包,地址,交易,也没有共识机制。
参考:https://jeiwan.net/posts/building-blockchain-in-go-part-2/