前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >区块链技术与应用02 北大肖臻

区块链技术与应用02 北大肖臻

原创
作者头像
Daffy
修改2020-11-12 11:17:18
1.3K0
修改2020-11-12 11:17:18
举报
文章被收录于专栏:密码学和区块链

BTC-挖矿难度

H(block\ \ header) \leq target ,target越小,挖矿难度越大,挖矿难度跟目标阈值成反比。调整挖矿难度,就是调整整个目标空间在整个输出空间所占的比例。哈希函数 SHA-256 ,整个输出空间大小为 2^{256}

difficulty_1_target 表示挖矿难度为1时所对应的目标阈值。挖矿难度最小为1,它对应的目标阈值是一个很大的值。

如果不调整挖矿难度的话,随着算力增强,出块时间越来越短。这样的话,很容易出现分叉。

比如出块时间是1s,那么很容易出现一个十分叉,然后假如有一个恶意节点想回滚之前的交易 A \rightarrow B ,按照之前的想法,恶意节点至少要拥有过半的算力,但是现在区块链中有一个十分叉,它将系统中的算力给分散了,而恶意节点可以集中算力扩展 A \rightarrow A' 的链,很容易让其成为最长合法链,因为诚实节点的算力被分散了。这种情况下不再需要51%的算力,可能10几%就够了。所以出块时间不是越短越好。

以太坊出块时间15s,设计出新的协议 ghost,分叉产生的 orphan block 不能够简单的丢弃,给一些简单的奖励 uncle reward。

怎么调整挖矿难度?比特币每2016个区块调整一次难度,需要两个星期。

公式。 time小,target变小,难度上升。目标阈值增大最多四倍。也就是如果actual time超过8周,只按8周计算。最小也是四分之一,不到半个星期也按半个星期算。

挖矿难度调整写在区块链系统代码中,每过2016个区块调整一次难度,恶意节点不调怎么办,mBits区域不可以通过。诚实的节点不认,合法性通不过。

比特币中算力增长趋势。

挖矿难度的增长曲线。

最近半年难度调整曲线。难度增长,反映出大家对比特币热情越来越高。

出块时间。10分钟左右。

最近半年的出块时间。10分钟左右。

挖矿难度的公式。和阈值调整相反。

BTC-挖矿

全节点的职责。缺省情况,沿着最长合法链挖下去,当出现等长的分叉,选择最先听到的那个分叉。

轻节点的职责。

正在挖矿,突然系统中有人挖到了节点,重新组装设备,挖下一个。并不可惜,因为 memoryless or progress free。

比特币是怎么保证安全性的?两方面,一方面是密码学上的保证,别人没有你的私钥,不能伪装你的签名,所以不能转走你账上的比特币。另一方面是共识机制,系统中大部分的矿工是诚实的。

挖矿设备。

第一代,CPU。资源闲置,性价比不高。

第二代,GPU。通用并行运算。但仍然有浪费,如浮点数计算。

Mining puzzle ASIC芯片,application specific integrated circuit,专门为了挖矿设计的芯片。一种芯片只能为一种加密货币挖矿。除了merge mining的情况。

Alternative mining puzzle ,抗ASIC芯片化(ASIC resistance),普通人也能挖矿。

矿池(pool)。

矿主(Pool manager)下面有很多矿工(miner)。 矿工计算哈希值。矿主监听网上的交易打包成候选区块,看看有没有其他节点抢先发布区块。一起分红。

如何分红?之前挖矿难度太难了,矿工要挖一两年才能挖到一个区块,收入不稳定,于是降低挖矿难度。矿工拿到share(almost valid block),提交给矿主。share是工作量证明。按提交的share数目分配利益。矿工任务由矿主分布。矿工不能自己发发布区块。CoinBase里面的收款地址是矿主的。有一些搞破坏的矿工,挖出来不提交,扔掉,别的矿池派来的间谍故意去搞别人的池子。

中国矿池算力占全球81%。

曾经有一个矿池(Ghash)算力达到51%,引起大家恐慌,然后主动减少算力,保护大家对比特币的信心。现在不再运营了。

矿主按比例抽取管理费。矿主降低管理费,吸引越来越多的矿工。就可以发动攻击。矿池加大了51%攻击的风险

分叉攻击。

先等六个区块让B放心,再让交易滚回去。看着追赶很漫长,但是因为矿主掌握了51%的算力,下面的链的平均增长速度比上面快。A \rightarrow B 交易会被回滚。

注意:不到51%也是可以发动攻击,这只是个概率问题。并且矿池的算力也只是估计而已。

Boycott攻击。

攻击者不喜欢A账户,想封锁A账户,所有和A有关的交易都不让上链。 没必要等六个区块。马上分叉。

没有人家的签名,所以盗币是不可能的

矿池实际上是On demand mining。自己不需要维护很大的挖矿集群,但是需要的时候,可以召唤。

BTC-脚本

比特币一个交易实例。包含一个输入两个输出。收到23个确认,回滚概率很低。下面是输入脚本和输出脚本。

输入脚本包含两个操作,分别把两个很长的数压入栈里,比特币所使用的脚本语言非常简单,唯一可以使用的内存空间就是一个堆栈,基于栈的语言(stack-based language)。

输出脚本有两行,分别对应上面的两个输出。每个输出有自己的单独的一个脚本。

首先看交易的一些宏观信息。

locktime:用来设定交易的生效时间。0表示立即生效,如果非0值,过一段时间才能生效。

vin,vout:输入输出部分,后面详细讲解。

blockhash:交易所在的区块的哈希值。

time:交易产生的时间。

blocktime:区块产生的时间。(表示从某个很早的时间点过了多少秒)。

txid:之前交易的哈希值。

vout:这个交易的第几个输出。

这两个给出了比特币的来源。这项交易所用的比特币来自 "c0cb...c57b" 交易的第0个输出。

输入脚本(scriptSig),最简单的形式给出一个签名(signature),证明我有权力花这个钱。后面的scriptSig用 input script代替。

如果一个交易有多个输入的话,每一个输入都要给一个来源和一个签名。比特币中的交易可能有多个签名。

value:输出的金额,单位是比特币。

n:序号,表示是这个交易的第几个输出。

输出脚本(scriptPubKey),最简单的形式给出一个公钥(public key)。

asm:显示输出脚本的内容,里面包含一系列的操作,后面详细解释。

reqSigs:需要多少个签名。

type:输出的类型。

addresses:输出的地址。

意思是想给谁钱,地址是那个人公钥的哈希。

首先执行输入脚本,再执行输出脚本,如果执行没有出错,最后栈顶的结果为TRUE,验证通过,交易合法。如果交易有多个输入,那么每个输入,都要和其对应的输出进行验证,验证通过,这个交易才是合法的。

第一种形式。P2PK

输出脚本里直接给出收款人的公钥。输入脚本里的签名是用私钥对这个输入脚本所在的整个交易的签名。

注意:现实中,为了安全考虑。是分开执行的。这里为了方便,放在了一起进行考虑。

脚本执行。首先分别将签名和公钥压入栈。

读到CHECKSIG,将栈顶两个元素弹出来,用公钥检测签名是否正确。注意这里交易是 A \rightarrow B 的输出脚本和 B \rightarrow A 的输入脚本。

实例。

第二种形式。P2PKH

这种形式最常用,这里输出脚本没有直接给出收款人的公钥,给出的是公钥的哈希值,公钥在输入脚本里给出。

脚本执行。

DUP:把栈顶元素复制一遍。

HASH260:把栈顶元素弹出取哈希值,再压入栈。

注意:这里栈顶有两个哈希值。上面这个哈希值是输出脚本里提供的收款人的哈希值。下面的哈希值是输入脚本里的公钥运行HASH160取得的。

加下来EQUALVERIFY弹出栈顶的两个元素,比较是否相等。作用是防止有人冒名顶替。假设相等,就从栈顶消失。接下来检测签名。

实例。

第三种形式。P2SH

最复杂。这里输出脚本给出的不是收款人公钥的哈希,而是收款人提供的一个脚本的哈希。这个脚本叫赎回脚本(redeemscript)。将来要花这笔钱时,输入脚本要给出赎回脚本的具体内容,同时也要给出让赎回脚本正确运行的签名。

进一步说明。

用P2SH实现P2PK。

第一阶段的验证。先验证用户给出的赎回脚本是正确的。

两个RSH相等,从栈顶消失。

第二个阶段的验证。首先将输入脚本中序列化的赎回脚本进行反序列化。然后执行赎回脚本。

然后检测签名。

这么复杂?为了多重签名。

比特币系统中一个输出可能要求多个签名才能把钱取出来。

多重签名。红色的x是因为系统实现的bug,在CHECKMULTISIG中弹出栈时会多弹出一个元素,用红色的x填补一下。

M表示需要M的签名,N表示N个人。N个人中M个人签名即可取钱。

注意:给出的M个签名的相对顺序要和他们在N个公钥中的相对顺序一致才可以。

脚本执行。

FALSE多余的操作。

存在的问题,用户需要知道N和M等等,写在输出脚本里,复杂性交给了用户,并不好。

用P2SH实现的多重签名。

本质把输出脚本里的复杂度转移到赎回脚本中。用户只需要知道赎回脚本的哈希值。

执行脚本。

第一阶段的验证。

第二阶段的验证。

实例。

一个特殊的输出脚本。证明销毁比特币的方法。

1.小币种(Alternative coin),除了比特币以外的其它小的加密币种,都可以叫做Alternative coin。销毁一个比特币,获得小币种,证明你付出了代价。

2.往区块链写入一些内容。比如一个知识产权,取哈希值放在RETURN的后面,永远保存,不会被篡改。任何用户都可以用这种方法销毁很少一点比特币,换取往区块链中写入一些内容的机会。注意,coinbase域写入内容只有拥有记账权的人才可以做到。

发布交易不需要有记账权,发布区块才需要有记账权。

实例。

coinbase交易。

普通交易。

缺少OP,比如 CHECKSIG 实际上是OP_CHECKSIG。

BTC-分叉

临时分叉(State fork)。由于对比特币区块链当前的状态有意见分歧而导致的分叉。分叉攻击(Forking attack),属于临时分叉。也叫做Deliberate fork。

Protocal fork。对比特币协议产生了分叉,用不同版本的比特币协议。包括硬分叉(hard fork)和软分叉(soft fork)。

硬分叉(hard fork)。

如果对比特币协议增加一些新的特性,扩展一些新的功能,这时,那些没有升级的旧节点不认可这些新的属性,认为这些特性是非法的,产生了硬分叉。

举例:Block size limit,1MB=1000000B,每个交易250B,大概是1000000/250=4000个交易。4000/(60*10)=7 tx/sec,每秒钟7笔交易。

有人发布一个软件更新,要求更新协议:1MB \rightarrow 4MB。大部分算力更新了软件,少部分没有更新。

分叉是永久性的。只要旧节点不更新软件,分叉就不会消失。

出现硬分叉后,之前旧链中的出块奖励还有没有用?出现硬分叉后,就变成了两条平行运行的链,这两条链彼此之间有各自的加密货币,变成了社区分裂,最后导致分家了。分叉之前的币按道理变成上下两条链都认可,一个币变成了两个币。

ETH已经分叉了,分出来个ETC。https://blog.csdn.net/woshilingdaoren/article/details/81808433

分叉之前有一笔帐 A \rightarrow B ,然后B拿到钱后,在分叉后的两条链上都可以花。所以,分叉之后,不采取某些行动,彼此之间会有影响。

举例:两条链之前由一条链分叉而来,之前的私钥账户不变,就是协议不一样,但账户的余额也是不一样的。但是上面有一笔 B \rightarrow C ,在下面的链回放。这样C收到了两笔币。

还有,比如,在上面的链,B在C那里购物,后来取消了订单,C将钱转回了B,B在下面的链回放。但是这样有风险,可能C重放b转给C的交易,但是B可能在下面的链没有钱。。。。。。。

解决办法:现在这两条链各带一个chain ID。

软分叉(soft fork)。

如果对比特币协议加一些限制,原来合法的区块在新的协议下不再合法,造成了软分叉。

举例:Block size limit:1MB → 0.5MB。大部分算力更新了软件,少部分没有更新。

是临时性的分叉。旧节点如果不更新软件,经常白挖。所以旧节点放弃了自己的链,跟到了长链。因为新节点不认旧节点,但是旧节点认新节点。系统不会有永久性的软分叉。

实际中会出现软分叉的情况:

给某些目前协议中没有规定的域增加新的含义,例如coinbase域,有一个用途,做为extra nonce提高挖矿难度。

但是coinbase域不止8个字节,有人提议后面的字节用来把UTXO集合的内容组织成merkle tree,算出根哈希值写入coinbase域。

coinbase域的值本身会被算法 block header 中的根哈希值中,这样就可以用 merkle proof 证明出全节点给出的账户余额是否正确。这是软分叉。

软分叉经典例子:P2SH(pay to script hash)。赎回账本(Redeem script),旧节点只做第一阶段验证,新节点两个阶段都验证。

总结。

Soft fork:只要系统中拥有半数以上算力的节点更新了节点,系统就不会出现永久性的分叉。会有临时性的分叉。

Hard fork:必须所有节点都要更新软件,系统才不会出现永久性分叉,小部分节点不愿意更新,系统就会分出两条链。

BTC-问答

  1. 转账时接收人不在线怎么办?不需要接收者在线,知道他的地址就行,离线没关系。
  2. 假设某个全节点收到了某个转账交易,有没有可能接收者的收款地址是这个节点从来没有听说过的?账户在创建时不需要通知其他人,只需要在本地创建一个公私钥对就可以了,当收款地址第一次收到钱时,节点才知道这个账户的存在。
  3. 账户私钥丢失了怎么办?莫办法,变成了死钱。没有人可以重置密码。比特币交易所处于缺乏监管的情况,并不安全。Mt Gox 交易所机构曾被盗并破产了。
  4. 私钥泄露怎么办?尽快把钱转到其他的安全账户上。公私钥对一旦生成,没有办法更改,所以更改不了私钥。只能再生成一个公私钥对,转账。
  5. 转账写错地址怎么办?没有办法取消已经发布的交易。转到了一个不存在的地址,地址比如是知识产权的哈希值,这样比特币也成了死钱,这个做法不提倡,会永久保存在UTXO里,对全节点不友好。
  6. 注意一点:当使用Proof of Burn时,将这个交易写入区块链进行验证时,并不会验证这个输出脚本,只会验证这个交易的输入脚本和来源的输出脚本,所以会被写入区块链。
  7. 挖矿就是尝试nonce,会不会有的矿工偷答案,偷别人的nonce,怎么知道是哪个矿工最先找到的nonce?发布的区块里有一个coinbase tx是收款人地址,要改成自己的地址,这样coinbase tx发生改变,导致了markle tree 的根哈希改变。nonce和根哈希都在block header里。block header 发生了改变,所以不可能偷答案。
  8. 怎么知道交易费该给哪个矿工?事先怎么知道哪个矿工挖到矿?事先不需知道哪个矿工会得到这笔交易费。只要total inputs>total outputs,差额就是交易费。哪个矿工挖到了矿,就把这些差额收集起来,作为自己的交易费。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • BTC-挖矿难度
  • BTC-挖矿
  • BTC-脚本
  • BTC-分叉
  • BTC-问答
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档