区块链之共识算法系列——PoW
一、前言
而我们的P2P,就是这样一个不需要经过第三方的概念,其之所以会出现的一个重要原因就是避免有第三方和中心。
在P2P对等网络中所有的节点功能都是一样的,没有哪一个节点是特殊的,他们之间互相提供服务。
因为没有第三方,没有中心,所以保证了数据的透明、自由、平等。
我们常听说的比特币就是使用PoW共识算法的。PoW是Proof-of-Work的简称,即工作量证明。就是计算一个数值,使得和数据合并后的值满足要求后,就马上广播全网打包区块,全网的节点收到广播之后,就会验证其正确性。如果节点有作弊行为,那么就不会通过验证,这个打包的区块会被丢弃,无法记录到账本,挖矿成本这么高,如果作弊导致区块被丢弃,比特币也拿不到了,岂不是还得亏本。所以矿工都愿意遵守比特币系统的共识协议。
二、生成创世区块
我们先定义区块的结构体:
type Block struct {
//上一个区块的哈希值
PreHash string
//当前区块的哈希值
HashCode string
//时间戳
TimeStamp string
//难度系数
Diff int
//交易信息
Data string
//区块高度
Index int
//随机值
Nonce int
}
根据比特币,我们将这个区块的信息设置为以下几点:上一个区块的哈希值、当前区块的哈希值、时间戳、难度系数、交易信息、区块高度、随机值。
然后我们来建立一个创世区块。
//创世区块
func GneFirBlock(data string) Block {
//创建第一个区块
var firstblock Block
firstblock.PreHash = ""
firstblock.TimeStamp = time.Now().String()
firstblock.Diff = 3
firstblock.Index = 1
firstblock.Nonce = 0
//通过sha256计算哈希值
firstblock.HashCode =GneHashValue(firstblock)
return firstblock
}
因为是第一个区块,所以前一个区块是为空,时间戳我们使用现在的时间,难度我们暂时设置为3,因为是第一个区块,所以区块高度为1,随机值可以随便搞一个,我们就用0吧。然后我们得计算当前区块的hash值,我们要使用sha256来计算。
三、生成哈希值
func GneHashValue(block Block) string {
var hashdata = strconv.Itoa(block.Index) + strconv.Itoa(block.Nonce) + strconv.Itoa(block.Diff) +
block.TimeStamp + block.PreHash
var sha = sha256.New()
sha.Write([]byte(hashdata))
hashed := sha.Sum(nil)
return hex.EncodeToString(hashed)
}
我们这个区块链是仿的比特币的区块,所以我们要将所有数据拼接在一起然后再求哈希值。这里我们使用的是sha256加密算法。这里先使用sha256.New,这个方法会返回一个hash.Hash。这个Hash实现了encoding.BinaryMarshaler和encoding.BinaryUnmarshaler,可以对哈希的内部状态进行编组和解组。然后使用Write将数据写入底层数据流,它会返回写入的字节数或者错误,这里我们不需要它的返回值。Sum方法我们这的参数是nil,这就说明我们要将当前的哈希值追加到nil,并返回生成的一个slice,这个方法不会改变哈希值的底层状态。EncodeToString返回hashed的十六进制编码。
四、看一看创世区块
我们来看一看创世区块。
func main() {
var firstBlock = GneFirBlock("Regan Yue")
fmt.Println(firstBlock)
fmt.Println(firstBlock.Data)
}
{ e42d311dd9ba42d8f1907ba60a7c1112c1720ccbdad938aaad91b4990089ece8 2021-11-06 21:34:32.3711993 +0800 CST m=+0.023002101 3 Regan Yue 1 0}
Regan Yue
我们可以看到,创世区块的数据就保存好了,然后我们来写生成新的区块。
五、生成新区块
func GneNewBlock(data string, oldBlock Block) Block {
var newBlock Block
newBlock.TimeStamp = time.Now().String()
newBlock.Diff = 3
newBlock.Index = 2
newBlock.Data = data
newBlock.PreHash = oldBlock.HashCode
newBlock.Nonce = 0
newBlock.HashCode = pow(newBlock.Diff, &newBlock)
return newBlock
}
接下来我们要生成一个新的区块,这里区块高度要为2,新区块的PreHash要为前一个区块的哈希值,然后我们计算这个区块的哈希值,这里我们模仿比特币,算前导0的个数。
func pow(diff int, block *Block) string {
for {
hashValue := GneHashValue(*block)
fmt.Println(hashValue)
if strings.HasPrefix(hashValue, strings.Repeat("0", diff)) {
//成功
fmt.Println("success")
return hashValue
} else {
block.Nonce++
}
}
}
如果生成的哈希值前导0的个数等于难度值就返回哈希值,否则Nonce值变化。
- 点赞
- 收藏
- 关注作者
评论(0)