区块链(二)

发布时间 2023-09-13 14:36:39作者: 筱倩

1. BTC——挖矿

(1)全节点

  • 一直在线
  • 在本地硬盘上维护完整的区块链信息
  • 在内存里维护UTXO集合,以便快速检验交易的正确性
  • 监听比特币网络上的交易信息,验证每个交易的合法性
  • 决定哪些交易会被打包到区块里
  • 监听别的矿工挖出来的区块,验证其合法性
    • 每个交易要合法,包括铸币、有没有篡改block reward出块奖励、发布的区块是不是符合难度要求的(block header取哈希值后就看前面有没有足够的0)
    • 检查block header里难度目标域值设置是不是正确的,全节点每两周要按照比特币协议的要求调整挖矿难度。
    • 检查这个区块是在延伸最长合法链。
  • 挖矿
    • 决定沿着哪条链挖下去
    • 当出现登场的分叉的时候,选择哪一个分叉?

(2)轻节点

  • 不是一直在线
  • 不用保存整个区块链,只要保存每个区块的块头
  • 不用保存全部交易,只保存与自己相关的交易
  • 无法检验大多数交易的合法性,只能检验与自己相关的那些交易的合法性。
  • 无法检测网上发布的区块的正确性
  • 可以验证挖矿的难度
  • 只能检测哪个是最长链,不知道哪个是最长合法链

【注1】比特币网络中大部分节点都是轻节点,如果只进行转账,不需要挖矿的话,就只用轻节点就可以了。

【注2】如果你监听到别人发布了一个区块,这个区块是合法的,也是在延伸最长合法链,此时你应停止已有的挖矿,然后重新在本地组装一个候选区块,再重新进行挖矿。因为如果沿着这个新发布的区块往下挖的话,本地所组装的区块中包含的交易就会发生变化,有些交易可能已经被包含到新发布的区块里面了,block header里内容也会变化,如block header里有这个交易所组成的merkle tree的根哈希值和指向前一个区块的指针,这些都会变化。这样做是可惜的吗?不是,因为挖矿是无记忆性的。

(3)比特币是怎么保证安全的?

  • 密码学:别人没有你的私钥,就不能伪造你的签名,所以就不能把你账上的钱转走。(前提:系统中拥有大多数算力的矿工是好的)
  • 共识机制:银行的工作人员要遵守规定,不会把钱交给没有合法证件的人。

(4)挖矿

  ①挖矿的设备(通用趋于专业化)

  • 第一代:最早用普通的CPU(家里的计算机、笔记本)挖矿,性价比太低。
  • 第二代:GPU,效率提高了,用于大规模的并行运算,有很多部件闲置,比如说用于浮点数计算的部件(适用于深度学习),比特币的挖矿只用到了整数操作。
  • 第三代:ASIC(Application Specific Indegreated )芯片,专门为挖矿(计算哈希值)设计的芯片,上面没有多余的电路逻辑,性价比最高。

  【注】为某种加密货币设计的ASIC芯片,就只能用于挖这种货币,不能挖其他的。除非这两个的mining puzzle一样。挖矿时求解的puzzle叫mining puzzle。有些加密货币在新发行的时候,为了解决能启动问题,故意用一个已有的加密货币的mining puzzle,这样可以吸引更多的人来挖矿——merge mining。 一款ASIC矿机刚上市的时候,大部分的利润是在上市前两个月获得。

  • alternative mining puzzle:新的加密货币,初衷是ASIC resistance,能抗AISC芯片化,目的是让通用的计算机也能参与挖矿过程。

  ② 另一个趋势:大型矿池的出现。单个矿工即使用了ASIC芯片挖矿,从平均收益上看是有利可图的,但是收入很不稳定。

  • 单个矿工还有另一个问题:除了挖矿之外,还要承担全节点的其他责任。引入矿池的概念,矿池就是把矿工组织起来,组织成一个整体。
  • 矿池的架构一般来说是:一个全节点会驱动很多矿机。一个矿池一般有一个矿主,一个pool manager下面连着很多矿工,它要负责监听网上的交易,把这些交易组织打包成一个候选区块,同时看看有没有其他节点抢先发布区块。
  • ASIC芯片只能计算哈希值,不能干全节点的其他功能。
  • 另一个目的:解决收入不稳定的问题。矿工和矿主可能不在同一个地方,矿工要加入一个矿池,就要按照这个矿池规定的通讯协议跟这个矿主进行联系,矿主把要计算的哈希值的任务分配给他。矿工计算完后把结果返回给矿主。将来有出块奖励的时候,一起参与分红。
  • 若矿工不是同一机构,那么利益如何分配?按每个矿工的贡献大小进行分配

  ③ 怎么证明每个矿工做了多少工作?

  • 为什么收入不稳定?因为挖矿太难了,如果降低难度,收入就会稳定。怎么降低难度?本来要寻找一个nouce,使得block header的哈希值前面至少有70个0,降低难度后:前面只要有60个0。这样挖到的叫做一个share alomost valid block。得到这个后交给矿主,除了作为矿工所做的工作量之外,没有其他作用,只是先收集起来,用于统计每个矿工所做的工作量大小。到时候真挖到矿了之后,再按大家的share数目进行分配
  • 问题1:有没有可能某个矿工挖到一个合法的区块后,不提交给矿主,而是自己偷偷发布出去,得到出块奖励不可能。每个矿工的任务是矿主发布的,矿主负责组装好一个区块,然后交给矿工去尝试各种各样的nounce。coin base transaction里面有一个收款人的地址,填的是矿主的地址。
  • 问题2:如果矿工一开始就无视矿主的任务,但是会把share交给矿主,这样矿主是不会承认他所做的工作的。
  • 问题3:有没有可能捣乱?平时挖到了share会上交给矿主,但是真正挖到了之后,不提交直接扔掉。矿池之间是有竞争的,可能是竞争对手派过来的矿工故意来捣乱。

  ④ 关于矿池

  • 大型矿池的弊病:使得51%的攻击更加容易。
  • 假设某个矿池占到了半数以上的算力,具体能发动哪些攻击?
    • 分叉攻击
    • boycott:封锁。攻击者不喜欢某个账户,所有跟这个账户相关的都不能上链。如果坏人有51%以上的算力,它公开抵制某个账户,那么别的矿工也不敢随意打包。
    • 攻击者拥有51%以上的算力后,把别人账上的钱盗走?不行
    • 如果是仗着自己算力强,强行把一个不合法的区块发布到区块链上?会造成分叉,诚实的矿工会沿着另外一条连往下挖。

  ⑤ 总结:矿池出现的好处:以前是”中奖“的概率很低,一旦中了就是大奖;现在是每天都有机会得到一点小小的奖励。危害是发动50%的攻击变得容易了,不一定自己要这么多算力,类似于云计算中的on demand computing,平时不用自己去维护很大的计算集群,需要用的时候可以随时召唤,这里是on demand mining。

2. BTC——比特币脚本

(1)比特币是一种基于栈的语言(stack based language),为的是让变量用完了就释放掉,就不会一直占用内存

(2)交易结构

  • 宏观信息

  “result":{

    "txid": "921a...dd24",  

    "hash": "921a...dd24",  //交易的哈希值

    ”version“: 1,  //使用的比特币协议的版本号

    ”size”: 226,  //交易的大小

    "locktime": 0,  //基本上都是0,表示立即生效

    "vin": [...],  //输入

    “vout”: [...],  //输出

    "blockhash": 0000000000002c510d...5c0b",    //这个交易所在区块的哈希值

    "confirmations": 23,      //这个交易有多少确认信息

    "time": 1530846727.      //交易产生的时间

    "blocktime": 1530846727    //区块产生的时间

  }

  • 交易的输入

  "vin": [ {

    "txid": "c0cb...c57b",    //之前交易的哈希值

    "vout": 0,        //来自交易的第几个输出

    "scriptSig": {      //输入脚本

      "asm": "3045...0018",

      "hex": "4830...0018",

    },

  }],

  • 交易的输出

   "vout": [ {

    "value": 0.22684000,    //交易的金额

    "n": 0,          //来自交易的第几个输出

    "scriptPubKey": {      //输出脚本

      "asm": "3045...0018",

      "hex": "4830...0018",

      "reqSigs": 1,      //这个输出需要多少个签名才能兑现

      "type": "pubkeyhash",  //输出的类型:公钥的哈希

      "addresses": ["...."]    //输出的地址

    }

  }],

 (3)有两笔交易:A->B,B->C,其中B->C中B的来源是A->B的B。TX B->C的输入指向A->B的输出。要验证这个交易的合法性,将B->C的输入脚本与A->B的输出脚本拼接在一起执行。早期是拼接在一起,从头到尾执行一遍,后来出于安全因素的考虑,改为先执行输入脚本再执行输出脚本,如果能顺利执行,交易就是合法的。

(4)输入、输出脚本的形式

  • P2PK(Pay to Public Key)
    • 脚本执行:输出脚本里直接给出收款人的公钥,在输入脚本里直接给出签名,这个签名是用私钥对输入脚本所在的整个交易签名,这种形式是最简单的。

    • 实例

  • P2PKH(Pay to Public Key Hash,最常用)
    • 脚本执行:输出脚本里没有直接给出收款人的公钥,而是公钥的哈希。输入脚本要给出签名+公钥,输出脚本的操作主要是验证交易的正确性。

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

  HASH160:把栈顶元素(公钥)弹出来,取哈希,然后把得到的哈希值再压入栈

  PUSHDATA(PubKeyHash):把输入脚本里提供的公钥的哈希值压入栈

  EQUALVERIFY:弹出栈顶的两个元素,比较它们是否相等(目的是防止有人冒名顶替)

  CHECKSIG:弹出栈顶的两个元素,用公钥检查是否正确,假设正确,则栈顶留下TRUE。

  【PS:如果执行过程中任何一个环节发生错误,比如输入给出的公钥跟输出里给出的哈希值对不上,或是输入里给出的签名和给出的公钥对不上,则此交易非法】

  【input相当于给这笔交易解锁,ouput始终指的是币来源的输出】

    • 实例

  • P2SH(Pay to Script Hash,最复杂)
    • 输出脚本给出的不是收款人公钥的哈希,而是收款人提供的一个脚本的哈希,这个脚本叫redeemScript(赎回脚本)。将来花费钱的时候,输入脚本要给出redeemScript的具体内容+让这个赎回脚本能正确运行所需要的签名。
    • 验证分为两个步骤:1)验证输入脚本里给出的赎回脚本是不是跟输出脚本里给出的哈希值匹配,如果不匹配的话,说明给出的赎回脚本不对。2)如果输入里给出的赎回脚本是正确的,还要把赎回脚本的内容当作操作指令执行一遍,看是否能顺利执行。

  【用P2SH】实现【P2PK】

 

   【PS:为什么要嵌入到赎回脚本里?】P2SH功能在最初版本的比特币里面是没有的,后来通过软分叉的形式加进去的,它常见的应用场景是对多重签名的支持。

  • 多重签名:比如某公司的账户要求五个合伙人中任意三个人签名才能把公司账户上的钱取走。有某个合伙人私钥泄露,问题还不大,因为还需要另外两个合伙人的私钥才能把公司的钱取走。同时,也为私钥的丢失提供了冗余:五个合伙人即使有两个人把私钥忘掉了,剩下三个人仍然可以把钱取出来,然后转到某个安全的账户上。
    • 【PS】比特币中CHECKMULTISIG实现有一个BUG,执行的时候会从对栈上多弹出一个元素,现在没有办法改了,因为是一个去中心化的系统,要想通过软件升级去修复这个BUG,代价是很大的。实际采用的解决方案是在输入脚本里栈上多压进去一个没用的元素。

    • 脚本执行

   【这么实现有什么问题?早期的多重签名是这样实现的,在实际应用中有些不方便的地方。比如,往上购物,某个电商使用MULTISIG,要求五个合伙人中任意三个人才能把钱取出来,用户在网上购物支付时生成的转账交易要给出这五个合伙人的公钥+n+m。用户怎么知道这些信息呢?需要购物网站公布出来,用户再填进去。不同的电商采取的多重签名规则不一样,给用户生成转账交易造成不方便。这就要用到P2SH】

  • 用P2SH实现多重签名:它的本质是把复杂度从输出脚本转移到了输入脚本(redeemScript),输出脚本只要给出赎回脚本的哈希值即可。(收款人)赎回脚本里要给出n个公钥,还有n、m。比如收款人是电商,她只要在往上公布赎回脚本的哈希值,用户在生成转账交易时把这个哈希值包含在输出脚本里即可。至于电商用什么多重签名规则对用户来说是不可见的。将来如果电商要改变签名规则,就只要改变输入脚本和赎回脚本的内容,然后把新的哈希值公布出去就行。对于用户来说,只不过是付款时哈希值发生了变化,与P2PH类似。
    • 脚本执行

  【第一阶段】

  【第二阶段】

    • 实例

  • Proof of Burn

  除了比特币之外的小的币种可以叫AltCoin(山寨币),要求销毁一定数量的比特币,才能够得到这个币种。(证明你付出过一定的代价,才能够得到小币种)

  往区块链里面写入一些永久存储的内容。比如你要证明在某个时间知道某些事情,如涉及到知识产权保护的,把某项知识产权的内容取哈希值后,把哈希值放在RETURN语句的后面(后面的内容不会执行,而且是哈希值,不会占太多地方或泄露知识产权的内容),将来如果出现纠纷,再把具体内容公布出去,就能够证明。以前说过的coinbase也是类似的方法,但是只有获得记账权的节点才能用。但这种方法任何人都可以用(发布交易不需要有记账权,发布区块才需要有记账权)。