最近简单了解了一下区块链相关的知识,做了一篇笔记记录一下。

1、去中心化货币

去中心化货币需要解决以下两个问题,接下来都会围绕这两个问题来进行展开:

  1. 谁有权发行货币
  2. 怎么验证交易的合法性

crypto-currency(加密货币) 用到了 SHA-256 哈希算法,其中有几个比较重要的性质:

  • collision resistance(防碰撞)。很难存在有两个输入 a 和 b ,其中 a≠b,但 H(a) = H(b)。
  • hiding(隐匿性)。哈希函数不可逆,类似生成数字签名一样。
  • puzzle friendly(解谜性)。要想使得计算得到的 hash 值在某一个范围之内,则只能够一个一个的输入去尝试,很难直接找到某个值使得其 hash 值在某一个范围内。

一个区块的发布要被认可,需要其中包含的交易合法,还有计算得到的区块哈希要小于等于一个目标值,这个计算,就是熟知的挖矿过程了。

每一个比特币的节点都会收集所有尚未确认的交易,将其归集到一个资料块中,矿工节点会附加一个随机调整数,并计算前一个资料块的SHA-256散列运算值。挖矿节点不断重复进行尝试,直到它找到的随机调整数使得产生的散列值低于某个特定的目标。

由于散列运算是不可逆的,查找到符合要求的随机调整数非常困难,需要一个可以预计总次数的不断试错过程。此时,工作量证明机制即发挥其作用。当一个节点找到了符合要求的解,那么它就可以向全网广播自己的结果。其他节点就可以接收这个新解出来的资料块,并检验其是否符合规则。如果其他节点通过计算散列值发现确实满足要求(比特币要求的运算目标),那么该资料块有效,其他的节点就会接受该资料块。

在比特币中,开立一个账户只需要一对公私钥 (public key, private key),其中利用到了非对称加密算法,加密用公钥,解密用私钥。而发起交易时,用私钥进行签名信息,外部的人用该公钥来进行验证是否是对应的账户发起的。

理论上,本地大量产生公私钥,然后对比网上的公钥,如果一致,可以尝试偷窃钱包。但由于是 256 位的哈希值,产生相同的公私钥的概率非常低。在生成和签名时,都需要有好的随机源。(比特币并不是直接把公钥暴露出来,而是取哈希后作为一个地址,像帐户信息一样,让对方汇钱。但取钱交易的话,就需要提供公钥了)

1.1、网路结构

比特币底层使用了 P2P 网络进行连接,保证其可用性和鲁棒性,但并不高效,它会采用 flooding 式(泛洪式)地广播。

这时候会存在竞争情况,因为一些交易会先在某部分节点传播,另一些在另一部分邻近节点传播,这个速度还需要考虑到带宽的因素,所以比特币会限制一个区块的大小为 1MB,尽量降低消耗。

如果一个帐户的交易都是从同一个 ip 发出的,那就很容易追溯到是谁了,因为存在关联性,所以为了保护比特币的匿名性,可以切换 ip 或者通过交易所来进行交易。

2、区块链结构

区块链使用的是哈希指针来连接到一起, 哈希指针要保存数据的地址,还要保存通过计算一个数据结构而得到的哈希值,每个新的哈希值都会依据前一个的内容(包括其哈希指针) 计算而得到,所以每个链区块内容息息相关,这样就可以防止篡改了。

我们只需要保存最近的一些链路区块就可以了,如果需要之前的,可以找有保存的人要,然后通过哈希指针去比对其内容的正确性。(实际结构并没有指针,只有哈希,这里用哈希指针只是形象地描述,由全节点来保存 key-value 去找到对应的区块)

所以挖矿的难度在于,需要根据前一个区块的信息,再加上随机数,来得到小于等于一个目标值。如果不是基于前一个区块,就形成分叉了,分叉的节点不一定能得到其他节点的认可。

2.1、区块信息

区块链只对 block header 进行取哈希的操作,其结构大致如下:

https://blockchain.info/ 可以看到一个区块的具体信息。

2.2、merkle tree

每个区块所包含的交易信息是使用 merkle tree 来进行保存的,叶子节点是交易信息,而子节点包含左右子树计算得到的哈希值对,这样就很容易知道哪个交易会出现异常了。

树的根节点,即根哈希值,是保存在 block header 里的,如何知道一个交易是否发生在一个区块里,这就需要 merkle proof 了,从自己的节点分支比对哈希值开始验证。 (如下图的绿色计算链条)

2.3、交易

系统节点分为全节点 full node 和轻节点 light node,全节点需要记录验证全部的完整区块信息,全节点会一直在线,负责监听交易信息和验证,当然也会进行挖矿操作。轻节点不会一直在线,只保存与自己相关的交易。

比特币使用的是 UTXO(Unspent Transaction Output) 交易体系,尽管可以单独处理 bitcoin,但要为转账中的每一分钱进行单独的交易会很笨拙。 为了允许值能被拆分和组合,所以一个交易可以包含多个输入和输出。

比特币基于 transaction-based ledger,从自己币的来源来验证其合法性(即从该币来源的区块一路验证币的合法性)。但每次转账需要把所有的币都花出去,比如 A 给 B 转 10 个比特币,那么 B 给 C 转 3 个比特币,还剩下 7 个比特币需要转给自己的新帐户,不然会变成交易费用。

2.4、attack

这里其实会有风险,因为链路可以分叉,区块链要如何防范 double spending attack(用同一笔钱同时进行多次交易)?

同样用到哈希指针,说明每个账户的币的来源和交易信息。当查出某个交易信息,通过向前比对检测交易者的币的来源,核对不正确,则此交易不合法。

这里旁观者也需要帮忙验证记录这些交易信息,所以交易者还需要在交易中,给出自己的公钥,来提供验证。

还有很多不同的攻击手段和方式。

女巫攻击是指个人试图通过创建多个帐户身份,多个节点或电脑坐标从而控制网络,因为比特币认的是最长合法链,控制了链路,就可以随意分叉了。下一节会讲区块链是怎么防范的。

selfish mining 即挖出来之后不马上发布,可以减少竞争,自己先继续挖下一个。但风险是,可能下一个自己还没挖出来,别人就挖出来现在的那个,导致要跟别人竞争挖出来的那个。

2.5、distributed consensus

对于区块记录的信息和顺序,需要 distributed consensus(分布式共识) 来保证。比特币是按照算力来进行投票决定的,决定是否接受区块的交易和顺序,找到 nonce,解 puzzle,才有记账权,才有权利发布区块。比特币接受的是最长合法链条,等长的话会接收最早的那条,但有可能会出现 forking attack(分叉攻击)。所谓认可区块,就是其他节点继续在后面扩展其区块。 一般可以多等几个合法区块的出现,才去确认之前的交易,防止突然被分叉。(发布交易不需要记账权,但发布区块需要)

形成共识大家就依据同样的规则去修改本地数据,从而保证了一致性。

不只是 forking attack,如果对区块参数进行修改,版本升级,也可能会出现分叉的情况。

为什么要消耗算力去争夺记账权,主要是可以得到奖励。一开始的币是可以从 coinbase transaction 凭空产生,出块可以奖励一定数量的币,随着出块越来越多,后续难度越来越难、出币也越来越少。光有出块奖励还不够,节点不一定会主动帮助打包你的交易,所以节点可以收取交易者少额的交易费。但即使当前节点不打包你的交易信息进去,后面可能也会有诚实的节点在下一个区块帮你记录下来。

2.6、挖矿

求解的过程可看成是 Bernoulli trial,平均出块时间可能是十分钟,这是以整体挖矿的平均时间来算的,单个矿工可能要很久,但即使挖矿时间已经十分钟了,继续挖出来的时间可能还是十分钟,即概率不相关。

挖矿难度会一直动态调整,防止过快被挖出来,每出 2016 个块会调整一次 (这个数字的设定并无解释和说明,来自于中本聪论文中的设置)。

每当发布出现一个新的区块,就需要重新基于新的区块进行挖矿操作。

现在还会有一些矿池的组织,组织大家算力一起合作挖矿,按照工作量来进行出块奖励的分配,即比如实际挖矿所需的 nonce 值要求前 30 位为 0,而如果比如矿工挖到 nonce 前 20 位为 0,这种称之为 almost valid block,就可以给矿主提供工作量证明了。

3、ETH

ETH 以太坊是以智能合约来进行组织的,而合同需要基于稳定的帐户信息,所以 ETH 是基于 account-based ledger 来进行交易,不需要查询币的来源,就像银行账户一样。这部分只做简略说明。

ETH 采用 merkle Patricia trie (MPT) 的数据结构,即经过路径压缩的字典树。value 使用 RLP(Recursive Length Prefix) 来进行序列化得来。 (算法不展开了)

如何判断一个元素是否在一个集合当中,比如判断交易是否在区块中,这里采用的是 bloom filter 布隆过滤算法。

ETH 的出块时间降到了 10 几秒,大算力系统会更占优,这样就很容易出现分叉的情况,导致挖矿出现无用功,这种被分叉而无效化的区块称之为 uncle block。

为了平等,ETH 底下使用 GHOST 协议,即如果当前区块把 uncle block 包含进去,可以得到额外的 1/32 的奖励,而挖出 uncle block 的可以得到 7/8 的奖励。(一个区块最多可以包含两个 uncle block,隔代数越多的 uncle block 得到的奖励会越来越少,过了 7 代就没奖励了。但只有分叉后的第一个区块可以得到奖励,在这个分叉节点再往后的就没有了。)

ETH 采用权益证明来进行投票,按获得的币的数量来进行股份制一样的维护,用一定的以太币和合同绑定,如果出现作弊或欺骗,则会被销毁。

3.1、智能合约

智能合约是运行在区块链上的一段代码,代码的逻辑定义了合约的内容。其帐户保存了合约当前的运行状态,包含当前余额、交易次数、合约代码、存储(MPT) 等。当然也可以用这段代码记录自己喜欢的东西和信息。

调用智能合约就相当于一次转账,只有合约帐户会有代码,而交易需要由外部帐户来发起,执行合约当中的代码需要收取汽油费(gas fee),由发起交易的人来支付。每个区块会有一个 gas limit 的限制,防止消耗过多的资源,矿工可以在前一个区块的基础上微调正负 1/1024。

Solidity是以太坊虚拟机(EVM)智能合约的语言。有个学习网站:https://www.wtf.academy/solidity-start,不同的代码写法所消耗的汽油费也不一样。

由于不可篡改性,所以即使发布的代码存在 bug,也没法修改,只能发布一个版本更新,但更新版本会导致出现分叉。这里可以看到一些漏洞的记录:Web3 security

而不能成功执行的交易,也要发布到区块上,这样矿工才能收取到汽油费。

参考