Loading

北大肖臻《区块链技术与应用》学习笔记6

BTC-脚本

  • 基于栈的语言

  • 单位satoshi(一聪),是比特币中最小的单位。1比特币=10的8次方聪

  • Locktime:等待时间,等待几个区块后才能写入区块

  • 比特币中check multisig的实现,输出脚本里给出N个公钥,同时指定一个预值M。输入脚本只要提供接N个公钥对应的签名中任意M个合法的签名就能通过验证。

    • 有一个bug,执行的时候会从堆栈上多弹出一个元素,这个就是它的代码实现的一个bug。这个bug现在已经没有办法改了,因为这是个去中心化的系统,要想通过软件升级的方法去修复这个bug代价是很大的,要改的话需要硬分叉。所以实际采用的解决方案,是在输入脚本里,往栈上多压进去一个没用的元素,例如第一行的“✘”就是没用的多余的元素。另外需要注意给出的M个签名的相对顺序,要跟它们在N个公钥中的相对顺序是一致的才行。
  • pay to script hash是现在多重签名的主流形式。这种脚本格式是比较特殊的,这种格式的输出脚本开头是return的操作,后面可以跟任意的内容。return操作的作用,是无条件的返回错误,所以包含这个操作的脚本永远不可能通过验证,执行到return语句,就会出错,然后执行就终止了,后面跟的内容根本没有机会执行。这个脚本是销毁比特币的一种方法。销毁比特币这个一般有两种应用场景:①有些小的币种要求销毁一定数量的比特币才能够得到这个币种,有时候把这种小币种称为AltCoin(Alternative coin)。除了比特币之外的其他小的加密货币都可以认为是Alternative Coin。比如有的小币种要求销毁一个比特币可以得到1000个小币,也就是说要用上述的方法证明已经付出了一定的代价才能够得到这个小币种。

  • 用pay to script hash实现pay to public key 的功能。这里的输入脚本就是给出签名,再给出序列化的赎回脚本,赎回脚本的内容就是给出公钥,然后用checksig检查签名。下面这个输出脚本是用来验证输入脚本里给出的赎回脚本是否正确。

  • Pay to Script Hash是最复杂的一种脚本形式,这种形式的输出脚本给出的不是收款人的公钥的哈希,而是收款人提供的一个脚本的哈希,这个脚本叫redeemscript,赎回脚本。将来花这个钱时输入脚本里要给出redeemscript(这个赎回脚本的具体内容),同时还要给出让赎回脚本能够正确运行所需要的签名。验证时分为两步,第一步验证输入脚本里给出的赎回脚本是不是跟输出脚本里给出的哈希值匹配,如果不匹配说明给出的赎回脚本是不对的,就类似于刚才讲的pay to public key hash里面给出的公钥不对一样。匹配不上说明给出的赎回脚本是不对的,那么验证就失败了。如果输入里给出的赎回脚本是正确的,那么第二步还要把赎回脚本的内容当做操作指令来执行一遍,看看最后能不能顺利执行。如果两步验证都通过了,那么这个交易才是合法的。

  • pay to script hash的执行过程。开始也是把输入脚本和输出脚本拼接在一起,前两行来自输入脚本,后面三行来自输出脚本。首先把输入脚本的签名压入栈,然后把赎回脚本压入栈,然后是取哈希的操作,得到赎回脚本的哈希。这里RSH是指redeem script hash,赎回脚本的哈希值。接下来还要把输出脚本里给出的哈希值压入栈,这时栈里就有两个哈希值了。最后用equal比较这两个哈希值是否相等,如果不等就失败了。假设相等,那这两个哈希值就从栈顶消失了,到这里第一阶段的验证就算结束了,接下来还要进行第二个阶段的验证

  • 第二个阶段首先要把输入脚本提供的序列化的赎回脚本进行反序列化,这个反序列化的操作在PPT上并没有展现出来,这是每个节点自己要完成的。然后执行赎回脚本,首先把public key压入栈,然后用checksig验证输入脚本里给出的签名的正确性。验证痛过之后,整个pay to script hash才算执行完成。

BTC-分叉

  • 分叉情况一:State fork 两个节点差不多同个时候挖到矿,出现的临时性分叉。是由于对比特币区块的状态有意见分歧而导致的分叉

  • forking attack属于state fork,人为造成,因此又称为deliberate fork

  • 分叉情况二:protocol fork (协议分叉)比特币的协议发生了改变,要修改比特币系统需要软件升级

  • 根据协议修改的内容不同,有分为硬分叉和软分叉

  • 硬分叉(hard fork):如果对比特币协议增加一些新的特性,扩展一些新的功能,这些时候那些没有升级软件的这些旧的节点,它是不认可这些新特性的,认为这些特性是非法的,这就属于对比特币协议内容产生了意见分歧,所以会导致分叉。(典型例子:区块大小限制 block size limit)

  • 避免硬分叉中出现双花攻击的情况,在两条链上加一个chain ID

  • 软分叉(soft fork):如果对比特币协议加一些限制,加入限制之后原来合法的交易或区块在新的协议当中有可能变得不合法。(典型例子:coinbase域)

  • Pay to script hash(P2SH)你支付的时候不是付给一个public key的哈希,而是付给一个赎回脚本的哈希。花钱的时候要把这个交易的输入脚本跟前面币的来源的交易的输出脚本拼接在一起执行。执行的时候验证分为两步,第一步是要验证输入脚本中给出的redeem script跟前面那个输出脚本给出的script的哈希值是对的上的,证明输入脚本里提供的script是正确的。第二步再执行redeem script,来验证输入脚本里给出的签名是合法的。

  • 对于旧节点来说,它不知道P2SH的特性,只会做第一阶段的验证,即验证redeem script是否正确。新节点才会做第二阶段的验证,所以旧节点认为合法的交易新节点可能认为是非法的(如果第二阶段的验证通不过的话)。而新节点认为合法的交易旧节点肯定认为是合法的,因为旧节点只验证第一阶段。

  • Soft frok只要系统中拥有半数以上算力的节点更新了软件,那门系统就不会出现永久性的分叉,只可能有一些临时性的分叉;特点是:必须是所有的节点都要更新软件,系统才不会出现永久性的分叉,如果有小部分节点不愿意更新,那么系统就会分成两条链

问题总结

  • 转账交易时接收者不在线
    这个时候不需要接收者在线,转账交易只不过是在区块链上记录一下,把一个人账户上的比特币转移到他人的账户上,他人是否当时连接在比特币网络上是没有影响的。

  • 某个全节点收到了一个转账交易,转账交易中接收者的收款地址是这个节点以前从未出现过的

    这是可能的。比特币账户在创建的时候是不需要通知其他人的,在本地产生一个公私钥对就可以了。只有在产生收款地址以后第一次收到钱时,其他节点才知道这个账户的存在。

  • 账户的私钥丢失怎么办
    私钥丢失之后是没有办法的。该账户上的钱就变成了死钱,永远取不出来了。在去中心化的系统里,是没有人可以给你重置密码的。有些加密货币交易时,一般来说交易所是中心化的机构。在交易所开办一个账户的时候,一般是要提供身份证明的。这种情况下把比特币保存在交易所里,私钥实际上是由交易所来保管的。登录这个交易所是按照登录银行差不多的程序,即一个账户名一个密码,一般来说需要二次验证,比如Google身份验证器产生一次性密码,通过二次验证然后登录。这种情况下如果账户密码丢失了,是可以跟交易所联系的,通过身份验证之后重置密码。有一些在线钱包也提供保管私钥的功能,但比特币或加密货币的交易所处于一种缺乏监管的状态,这个跟股票交易所是很不一样的。历史上曾发生很多次加密货币的交易所被黑客攻击的情况。

    • 最著名的是日本的Mt.Gox的事件,它曾经是全世界最大的一个比特币交易所,交易量占到了全球比特币交易量的70%,后来被黑客攻击,丢失了大量的比特币。后来交易所破产了,其CEO被判刑。各种加密货币交易所出现问题的情况发生了很多次,也有内部监管不当,管理人员卷钱跑路也时常发生。相比之下,一些冷钱包和硬钱包是比较安全的。
  • 私钥泄露怎么办
    当发现自己账户上出现一些可疑的交易时,应该尽快把自己账上的钱转到另外一个安全的账户上。比特币账户所谓的密码就是它的私钥。公私钥对生成之后是没有办法改的。可以生成一个新的账户,但是原来账户上的私钥是改不了的。同样,也无法阻止别人发布从这个账户上转账的交易,任何有私钥的人都可以发布一个转账交易,把账户上的钱转走,这个也是没有办法冻结的。所以我们能做的就是在第一时间抢在别人之前把自己账户上的钱转到一个安全的账户上。

  • 转账写错地址怎么办
    这是没有办法的。写错了地址而转错了人,我们也没有办法取消已经发布了的交易,比特币当中转账交易一旦发布到区块链里,就没有办法取消了。当转错了地址,如果我们知道是转给了谁,可以跟对方进行联系。如果不知道转的是谁的地址,或者是不存在的地址,那就没有办法了。

    • 什么叫不存在的地址,地址是公钥取哈希得到的。有些地址其实不是公钥的哈希得来的,比如digital commitment。你想把某项内容的哈希值发布到区块链上,证明你曾在某个时间知道某个事情。
    • 比如把哈希值放到return的后面,因为OP_RETURN后写什么都是没有人管的。但是有人会用哈希值生成一个看上去像是比特币地址的东西。比如A→B,正常情况下B是某个比特币账户公钥取哈希之后得到的地址。在这里把他要保存的那个哈希值生成一个地址,作为收款人的地址。这个地址是没有对应的私钥的,它其实是个假的地址,比特币系统并不知道这个地址的真假,你这个哈希是怎么来的,别人也看不出来。所以这样转账的钱就变成了死钱。这个转账永远不可能被取出来。
    • 这种做法一般牺牲一点比特币,比如转很少一点钱,换取往这个区块链里写入这个哈希值的机会。这个做法是不提倡的,因为这样的话转账交易的输出会永久的保存在UTXO里面。全节点收到这样一个转账交易,它其实并不知道你的地址的真假,它不知道你的钱其实是花不出去的,所以它必须把它永久的保存起来,这样对全节点是不友好的。
  • proof of burn 、OP_RETURN这些实际当中是怎么操作的
    当一个全节点收到一个转账交易的时候,它首先要检查一下,这个交易的合法性,只有合法的交易才会被写入区块链里。而OP_RETURN这个语句是无条件的返回错误,因此,验证当前交易合法性的时候,不会执行这个语句。即当前交易的输出脚本在验证交易合法性的时候,是不会被执行的。只有有人想花这笔钱,后面再有一个交易,要花这个交易的输出的时候才会执行这个交易的输出脚本。

  • 挖矿时会不会有的矿工偷答案
    不会。发布的区块里有coinbase transaction,里面有一个收款人地址,是挖到矿的矿工的地址。假如A挖到了矿,里面就是A的收款地址。如果要偷答案的话,就要把A的地址换成自己的地址,而地址如果一变化,coinbase transaction的内容就发生了改变。这将导致merkle tree的根哈希值变化,因为这个交易和区块中所包含的其他交易是合在一起构成了merkle tree。任何一个地方发生改变,根哈希值就会变。而nonce是在块头里面,根哈希值也是在块头里面,block header的内容发生了变化之后,原来找到的nonce就作废了。所以不可能偷答案,因为每个矿工挖到的nonce是和他自己的收款地址绑定在一起的。

  • 怎么判断交易费该给哪个矿工
    事先不需要知道哪个矿工会得到这个交易费。交易费的算法:total inputs>total outputs,其差额就是交易费。发布的交易里面,一个交易可以有很多个输入,也可以有很多个输出,总输入减总输出就是交易费。给谁不需要事先知道,哪个矿工挖到矿了,就可以把这个区块里所包含的交易差额收集起来,作为他自己的交易费。

posted @ 2021-07-30 10:32  潜仁  阅读(330)  评论(0)    收藏  举报