Proof of Work 工作量证明

前言

在区块链中每条链或多或少都各自发展出自己不同的共识机制,例如 Proof of Work、Proof of Stake、Proof of blah blah blah 等等之类,其概念基本上是让使用者付出代价,让使用成本升高从而确保安全性,其中比较着名的就是比特币使用的 Proof of Work(POW) 工作量证明,也是此篇文章的主旨。

介绍

某些网站在你登入或注册前会要你做一些烦人的益智题目,例如:选脚踏车、路灯或是移动拼图等等,这些题目拖慢了使用者注册和登入,看似破坏了使用者体验且没甚麽好处。但事实上是,对於一个愿意花时间做这些验证的人,我们姑且就相信他是一个"真人"使用者,因为他做了一些题目提出了证明。

同样的概念用在比特币区块链上,工作量证明就是让挖矿者花时间算数学题目,目前算一个区块需要 10~15 分钟的时间,对於愿意花时间来算题目的节点,我们就认证他是一个合格的节点。此外,由於工作证明是基於同样资料会得出同样结果的杂凑函式,所以其他的节点也能去验证新区块的正确性。藉由工作证明增加写入的困难度增进网路的安全性,若恶意节点想要窜改资料,他必须花上全节点加总 51% 以上的算力才有可能成功。其他的应用如最初是 Hashcash 运用工作证明的方式来防止大量的垃圾信件,其中工作量证明的演算法也叫做 Hashcash 演算法。

原理

工作量证明证明的数学题概念上很简单,给定一个固定的资料型态,并且去调整一个可变的随机数 nonce,使得杂凑出来的符合难度的结果。

https://ithelp.ithome.com.tw/upload/images/20210418/20123459N9XGy3Tpcu.png

然而何谓难度?以比特币系统来说,就是杂凑完的结果前缀有几个'0'字符,而由於杂凑出来结果是用 HEX 编码(16 位元) 的方式去转回字串所以每晋升一个难度会是前一个难度的 16 倍,范例如下:

// 难度1 可能性 1/16
"0treca8b5e0361a0c063db6ad77dc4b23369b9f5de85e4842539c381c333e99d"
// 难度2 可能性 1/256
"00reca8b5e0361a0c063db6ad77dc4b23369b9f5de85e4842539c381c333e99d"
// 难度3 可能性 1/4096
"000eca8b5e0361a0c063db6ad77dc4b23369b9f5de85e4842539c381c333e99d"

难度越高则所花费的时间越久,笔者单机手动测试难度为 5 大概花 0.57 秒,而难度为 6 则需要花费 8.71 秒。
目前的比特币难度是 20 以上,可知道为何人人说比特币是很耗资源的东西。

而在验证工作证明的方式也极其简单,就是把固定的资料和随机数做一次杂凑,去比对难度是否符合需求就可以。

实现

这里做出一个假设案例,目前我们希望做一个应用在注册帐号的工作量证明防止他人大量制造帐号:

package main

import (
	"crypto/sha256"
	"fmt"
)

// 注册资料格式
type Registraction struct {
	username  string
	password  string
	timestamp int64
}

// 回传给服务器的结果
type Data struct {
	registraction Registraction
	nonce         uint // 计算工作证明的随机数
}

func main() {
    // 注册资料
	register := Registraction{
		username:  "test",
		password:  "test123",
		timestamp: time.Now().UnixNano(),
	}

    // 难度
	difficulty := 6
	data := Data{register, 0}
	s := fmt.Sprintf("%v", data)
	
    // 主要的 hash 函式
    result := sha256.Sum256([]byte(s))

    for !isValid(difficulty, fmt.Sprintf("%x", result)) {
		data.nonce++
        s = fmt.Sprintf("%v", data)
		result = sha256.Sum256([]byte(s))
	}
	fmt.Printf("hash result: %x\n", result)
	fmt.Printf("Data result: %v\n", data)
}

// 检测结果是否符合标准
func isValid(difficulty int, signature string) bool {
	for i := 0; i < difficulty; i++ {
		if signature[i] != '0' {
			return false
		}
	}
	return true
}

结论

工作证明可以防范大量请求,从无延迟请求到设定所需时间的工作证明来验证使用者来达成目的。以上面范例来说,使原本创大量假帐号的效率可能从每秒 1 万个降低成每分钟只能创建 1 个的程度,大大加大恶意使用者的成本的简单机制。

参考

Hashcash Wiki:
https://en.wikipedia.org/wiki/Hashcash

比特币白皮书:
https://bitcoin.org/bitcoin.pdf

How do miners validate transactions:
https://medium.com/@blairlmarshall/how-do-miners-validate-transactions-c01b05f36231

如果有错误或其他意见欢迎提出


<<:  【心得分享】第一周心得分享(4/12~4/18)

>>:  创作者的商业思维-笔记

Day.3 天秤的两端

为了解释时间跟空间的取舍,来一条leetcode的题目,就是最经典的第一题Two Sum 输入一组a...

Rust-值,变数,物件

不应将值,变数,物件混淆为一体 单词"值"表示抽象的数学概念, 例如值:&quo...

Hello, OS!

资料传输 常见的资料传输方式有两种: Serial 将一串资料拆成多个资料,一次传一个资料。 pro...

第40天~还是JSON

这篇的上一篇:https://ithelp.ithome.com.tw/articles/10283...

网路是怎样连接的(三)浏览器与HTTP

思考重点 网页浏览器怎麽获取网站消息 当我们输入网时会发生什麽事 常见的404 not found意...