《区块链技术与应用》北大.肖臻

1 课程简介

区块链特征

不同观点:
下一代货币,
最慢数据库,
panzi骗局,

基础铺垫知识

数组,链表,二叉树,哈希函数;
参考资料:
BitCoin and Cryptocurrency Technologies
以太坊白皮书,黄皮书,源代码;
Solidity文档;

有关hash与加密的介绍《哈希(Hash)与加密(Encrypt)的基本原理、区别及工程应用》:
https://www.exyb.cn/news/show-3847402.html?action=onClick

2 密码学原理

加密货币crypto-currency
BTC主要应用密码学中的hash运算与数字签名;

Hash

cryptographic hash function
两个性质:

  1. 性质一:collision resistance:防止hash碰撞,两个不同值的hash值相同;输出空间大小2^256,输入空间无限制;碰撞理论上存在,但是没有高效方法人为制造碰撞;
    可以利用collision resistance性质做数据校验;
    collision resistance性质无法证明,只能用实践检验;MD5已经被找出了可以人为制造hash碰撞;
  2. hiding:hash值没有泄露有关输入的任何信息;利用hash无法推算出输入;
    hiding性质成立的条件是输入空间很大,且取值均匀,则无法用蛮力破解。
    hash校验可以用来:
    digital commitment;
    digital equivalent of a sealed envelope;

如果输入空间不是非常大,或者分布不是足够均匀的情况下,通常在输入数字后面拼接随机数作为整体的输入:H(x+nonce);
3. puzzle friendly:hash输出不可预测;若希望将hash值落在指定的区间,没有很好的方法找到输入,只能不停尝试;
difficult to solve, but easy to verify;
比特币的hash函数为SHA256(Secure Hash Algorithm);

Sig

开户:创立公钥私钥对。
非对称加密体系(asymmetric encryption algorithm)
签名用私钥,验证签名用公钥;
加密用公钥,解密用私钥;

攻击方法:不断产生公私钥对,直到产生与别人相同的公私钥对。
这种攻击不可行,产生相同公私钥对的概率非常小。

生成公私钥对需要很好的随机源;
签名也需要有很好的随机源;如果签名随机源不好,可能泄露私钥;

BTC中先对信息取hash,然后对hash签名。

3 BTC数据结构

hash pointers

哈希指针
存放数据地址+hash值;
可寻找到数据,并且校验数据是否被篡改;

区域链与普通链表的区别

  1. 用hash指针代替普通指针;
    区块链例子:
    创始区块(genesis block) <- (hash指针) 中间区块 <- …<-最新区块(most recent block)

tamper-evident-log:哈希指针存放了前面所有链表信息,只要链表被篡改,后级的hash校验就对应不上。

实际系统中,每个区块会包含很多交易,每个区块分一颗Merkle,为块头和块身两部分.

Merkle tree

一种数据结构
Merkle tree与binary tree的区别:

  1. 用hash指针代替了普通指针;
    (1)data block;
    (2)树状的hash指针;
    (3)根部root hash可以校验全部树结构中的数据;

每个区块分两部分:

    1. block header:根hash值;
      宏观信息:版本(Version),
      前模块的hash(hash of previous block header)
      整Merkle tree的根hash(Merkle root hash)
      挖矿难度目标阈值target;
      随机数nonce;
      要求:H(block header)<=target
      寻找随机数nonce使得block header满足以上关系,这个过程需要一定的算力;
      Q:target取值怎么取得?
      根据计算难度(平均出块时间),大约两周(2016个出块数量)调整一次。
    1. block body:有交易具体内容;
      保存了大约10分钟间隔内新产生的交易列表;
      作用:可提供Merkle proof;

全节点(fully validating node):包含block header与block body;
轻节点(light validating node):仅包含block header;
思考:轻节点怎么证明交易过程?
向全节点申请获取树结构数据中的部分关键数据(缺失的有效数据),轻节点利用这些数据计算拼接得到root hash;

基于此问题的继续思考:

如果验证结果正确,可证明某次交易是正确的;如果验证结果错误,就一定是交易记录错误吗,会不会是从全节点那里获取到的数据错误?
分布式系统可靠的前提是“大多数节点都是诚实的”,轻节点完全信任全节点提供的信息。

思考:

轻节点为什么需要验证某次交易?
轻节点怎样查询某次交易?是先找到区块,再找里面的交易?还是直接找交易?

collision resistance性质:人为制造hash碰撞不可行;

proof of membership/proof of inclusion:验证交易;计算复杂度,对数级;

proof of non-membership:按照交易叶节点的hash进行排序,在有序的叶节点中查询某个交易是否存在;

Sorted Merkle tree:叶节点有序排列,可以快速执行不存在证明;

无环数据结构可以使用hash执行代替普通指针;
环状数据结构使用hash指针会有问题:计算hash值的循环依赖;

4 BTC协议

如何设计出加密货币?
例如,央行发布数字货币:
货币信息:明码数字+加数字签名;
用户:用央行公钥验证加密数字是否为明码数字;

如何防止“花两次攻击”(double spending attack)?
这是数字货币面临的主要挑战。
尝试方案一:央行维护大数据库,记录数字货币在谁手中;
此方案缺点:这是中心化方案,每次交易都需要央行数据库的参与;

如何去中心化?
这是比特币系统要解决的问题。
区块链数据结构,维护货币的交易信息。

铸币交易(凭空产生的货币):没有输入,只有输出;
BTC交易包含输入和输出两部分:
(1)输入:说明货币来源;
(2)输出:给出收款人公钥hash;
交易消息中包含花费者的签名;

A spent to B:
A needs B’s public key’s hash;
B needs A’s what? needs A’s public key, all nodes need A’s public key, to verify A’s signed.
Question: how to know A’s public key?
If someone say A’s public key, check it use A’s money context, the hash in it.
花钱者A需要收钱者B的公钥,这公钥的来源是B告诉A的;
收钱者B以及所有节点都需要知道A的公钥,用A货币交易信息中的签名,校验A的公钥合法性;

交易记录是如何被用户记录的?
去中心化的账本,如何做到一致性?
账本的内容,要取得分布式的共识(distributed consensus)。
分布式的哈希表(distributed hash table)
FLP不可能结论(FLP impossibility result):在一个异步系统(网络延迟没有上限)中,即使只有一个成员是有问题(faulty)的,也无法达成共识。

CAP Theorem(Consistency, Availability, Partition tolerance):三个性质最多只能满足两个;

分布式系统的三个性质:
Consistency:一致性;
Availability:有效性;
Partition tolerance:误差容忍;

分布式共识(distributed consensus)的一个著名协议Paxos:
如果可以达成共识,那么共识结果一定是一致的;
但是,某些情况下,可能永远无法达成共识;

Consensus in Bitcoin

比特币中的共识
大多数节点无恶意,少数节点有恶意,怎样设计共识协议?
尝试方案一:投票方法
存在问题:membership,首先要确定谁有投票权;
hyper ledger联盟链协议,如fabric;
在比特币系统中,产生公私钥对就是一个账户,别人无法衡量账户合法性;
女巫攻击(Sybil attack):一台机器产生很多账户,多于系统半数用户,就拥有了系统控制权;

比特币系统采用计算力投票;
hash rate:每秒尝试计算hash找出nonce的次数;
一台服务器的账户增多,并不会增加其hash rate能力;
在计算区块,求解nonce的过程,被称为挖矿mining;

验证double spending(两次花费)的方法:一个分支上是否被花费两次;

分岔攻击(forking attack):
非法操作:创建分支,花费两次;
不在最长合法链的交易,不合法;

如果两个节点同时获得了记帐权,同时产生了分支,产生了等长的分支,如何处理?
每个节点仅接收最早接收到的区块;等长的临时性的分岔会存在一段时间,直到某一分岔找到下游区块被延长,另外一分支成为orphan block被丢弃,同时由该节点获得的出块奖励也将作废;

凡是合法的交易,都应该被写入区块链中,如何做到?

block reward,出块奖励;
谁有权利造币?
coin-base transaction 造币来源;
记帐节点,被奖励一定数量的比特币;
首期,50BTC,21W次交易区块后,奖励减半,变为25BTC;再21W,再减半成为12.5BTC;

平均每10分钟记帐一次,奖励递减一次的时间:
21W10分钟/(6024*365) = 3.99年;

总货币数量:
呈现几何序列(geometric series)
21W50(1+0.5+0.25+…) =21W502 = 210W;

每个块最多1M字节大小。
问题:每年区块链增加的数据大小为3652460/10*1M=51.3G。逐年累积,这个链条数据是否太大?

5 BTC 实现

05-上

transaction-based ledger

比特币采用的是基于交易的账本模式(transaction-based ledger)
还没有被花掉的货币UTXO: Unspent Transaction Output;
UTXO数据结构的作用?为了检测double spending;
自己正在花销的货币,必须在UTXO中;

每个交易可以有多个输入多个输出,所有输入金额相加等于所有输出。
total input = total outputs
有些交易,输入略大于输出,多出的那一部分,由记帐者获取。
如果只有出块奖励,那么自私节点仅打包自己的交易,不记帐其它交易。
“交易费”用来奖励记帐打包者。
在很多年后,出块奖励减少,记帐奖励变为主要收入来源。

accout-based ledger

基于账户的模式;

05-中

Bernoulli trial : a random experiment with binary outcome;
Bernoulli process: a sequence of independent Bernoulli trials;
progress free:过去的尝试对后续的发生概率没有影响;
progress free是挖矿公平性的保证,否则高算力挖矿者会有不成比例的优势;

BitCoin is secured by mining.
挖矿(产生交易记帐区块)的过程,对于维护比特币系统的安全至关重要;
系统的维护掌握在大部分诚实节点手中;

05-下

不诚实节点的欺骗:

  1. 伪造别人转账给自己:由于没有别人的签名,交易不被认可;
  2. 花两次,同时给别人转账,又给自己转账,在等长的分岔链条上,继续延长传给自己的那个分支。怎么防范?先转账,后发货,如果发现转给别人的交易不被认可,则不发货。那么如何处理“实时”交易?BTC不适合处理像信用卡这样的实时交易,交易确认至少要等待10分钟(一次出块时间)。
  3. Selfish mining:挖掘后不及时发布,等待别人发布后再发布,在自己发布之前,沿着自己的分支继续挖掘下一块。

06 BTC 网络

06上

The Bit Network.
比特币工作在应用层。
application layer: BitCoin Block chain;
network layer: P2P Overlay Network;

特征:simple, robust, but not efficient;
消息传播在网络中,采取flooding的方式;
节点传播是随机的,不考虑网络拓扑结构。

如果两个冲突节点,差不多的时间广播到网络中,有些节点收到A->B,有些收到A->C。
新发布的交易传播方式,与新发布的区块的发布方式是类似的。

06下

比特币去中心化网络遇到的问题:
不同节点收到的节点顺序是不同的;
有些恶意节点不按照比特币协议转发,有些转发不合法的交易;

07 BTC 挖矿难度

挖矿难度

在header中不断调整nonce值,使得整合header的hash值,小于target阈值。
SHA-256有256位,2^256种取值。
挖矿难度最小为1,表示为 difficulty_1_target;
挖矿难度计算:difficulty = difficulty_1_target / target;
注意:挖矿难度与目标阈值成反比;

调整挖矿难度的原因

随着参与者的增加,总算力的增强,不调整难度,出块时间会变短。

出块时间变短,会带来什么问题?
两个节点同时挖矿,同时出块。如果出块时间变短,产生分岔的概率会增加,并且不止有二分岔,而且会存在多分岔。分岔数量越多,对系统达成共识是不利的。
如果只有二分岔,恶意节点的数量达到51%才能破坏系统。但是10分岔后,11%就可以攻击系统,因为善意节点的算力被分摊了。

对于一个支付时间,一次交易要等待10分钟才能确认,有些太长。
以太坊对此进行了改进,出块时间是比特币的40倍。

怎样调整挖矿难度?

大约每2周调整一次难度。每2016个区块,调整一次难度。
201610分钟/(6024)=14天;
具体调整方法,按照公式:
target = target * actual_time/expected_time;
actual_time:最近2016节点的实际花费时间;
expected_time:201610分钟;
实际代码中,防止意外发生,actual_time有上下限制的限制[0.25
expected_time, 4*expected_time];

如果有恶意节点,到期后,不调整难度。会怎样?
如果不调整难度,恶意节点发布的区块,诚实节点不会承认。

思考:比特币的挖矿难度,比特币的计算能力(hash rate),比特币的市值的关系。

8 BTC 挖矿

全节点:

一直在线;
在本地硬盘上维护完整的区块链信息;
在内存里尾部UTXO集合,以便快速检验交易的正确性;
监听比特币网络上的交易信息,验证每个交易的合法性;
决定哪些交易会被打包到区块里;
监听别的矿工挖出来的区块,验证其合法性;
挖矿:(1)决定沿着哪条链挖下去;(2)当出现等长的分支,选择哪一个分支;

轻节点:

不是一直在线;
不用保存整个区块链,只需要保存每个区块的header;大小差别100倍;
不用保存全部交易,只保存与自己相关的交易;
无法检测大部分交易,只能检测与自己相关的交易的合法性;
无法检测网上发布的区块的正确性;
可以验证挖矿的难度;
只能检测哪个链最长,不知道哪个是最长的最长合法链;
注意:轻节点假设全节点是诚实的。

比特币系统中,大多数节点属于轻节点,并不参与挖矿。

如果在出块过程中,新产生了交易,之前的挖掘计算对象需要改变,重新计算,这是否可惜?不可惜,因为progress free的特性,挖掘成功的分布为概率事件,不具备记忆性。

随着挖矿的激烈竞争,挖矿工具由CPU转为GPU,实现大量的并行计算。
GPU中浮点运行对于深度学习有用,但与对于BTC挖矿计算无用。
现在采用ASIC(Application Specific Integrated Circuit)挖矿;

新矿机的50%利润在其生命的前2周创造的。

有些新的加密货币,采用Alternative mining puzzle,设计出点是ASIC resistance,使得通用的计算机也可以参与挖矿过程。

矿池 pool

pool manager下面有很多矿工miner;
miner仅仅负责计算hash值,全节点的其它职责由pool manager实现;
pool manager的出现解决了收入不稳定的情况。

收益如何分配?
按照每个矿工的工作量分配。
每个矿工如何证明自己的工作量?

share:almost valid block;(比如target比要求的大一些)
每个矿工输出几乎符合难度要求的块(share),将其提供给矿主。
矿主拿到这个块后,将其作为矿工的工作量证明。

有没有可能一个矿工挖到合法块后,不提交给矿主,自己偷偷的发布?
这是不可能实现的,矿主给矿工分配工作。因为CoinBase中提供的出块收获人地址为矿主的地址,这个内容会参与root hash的计算,作为工作量证明。

9 BTC 脚本

10 BTC 分叉(fork)

分叉的原因:
1.state fork: 由于对当前状态有歧义而产生的分叉;两个节点同时挖到矿;forking attack/deliberate fork;
2.protocol fork 比特币协议发生改变,分布式系统无法按时升级软件,由于协议内容不同,又分为hard fork, soft fork;

hard fork

如果对比特币协议增加的新特性,没有升级软件的旧节点,不认可这个块;
例子:比特币区块大小限制(block size limit);
一个交易250字节,1M包含4000交易,用时10分钟,平均每秒7比交易。这个交易数量太小。
很多人认为区块太小,限制交易的频率,需要增加block size limit,提升每个区块的记帐数量。
如果有人发布软件更新,将block size limit从1M增加到4M。大多数节点已经更新,少数节点没有更新。现在新节点产生新区块A,新节点认可,会沿着A继续挖,旧节点不认可,继续挖出B。因为新节点数量多,会使得A分支继续加长,就节点永远不承认A分支,这种分叉永远存在,所以称为Hard fork。

在真实案例:两条分支永远分家。在这中案例中,B转账给C,在两个链条上发生了两次(各一次),这样C收到两次。为避免转账在两条链条同时发生,各条链都带chain ID,独立记帐。

Soft fork

例子:比特币区块大小限制(block size limit);大多数新节点size改小。
新协议块小,算力多,所以生长的最快。
旧协议产生的分叉总是临时的,不被大多数新协议节点认可,这样对旧协议节点不利,会促进旧协议节点升级软件协议。

Coin-Base域:
可以作为extra nonce(前8字节),调整后增加解的搜索空间。
后面的字节,有人建议,可以将其作为UTXO的root-hash;
怎么计算A账户上有多少钱币?全节点才可以计算,轻节点无法知道。有人提议,将UTXO组织一棵Merkle-tree,将其hash写入coin-base;

10 BTC 问答

1. 转账时候是否需要接收者在线?

不需要,转账只是转出者将交易信息发布到比特币网络中,不需要接收者在线。

2. 加入某个全节点收到某个转账交易,有没有可能转账收款地址是从来没出现过的?

可能。比特币账户的创建,无需对外广播。

3. 如果比特币账户的私钥丢失(自己找不到),该怎么办?

没有办法处理账户的钱,这个钱变成了死钱。
在去中心化的系统中,没有重置密码的办法。
思考:银行系统中,用户的登陆是账户名称,密码,动态口令等。银行系统中有私钥吗?

4. 如果比特币账户的私钥泄露(别人和自己同时知道),自己账户出现可疑交易,该怎么办?

账户泄漏是别人和自己同时知道自己的私钥,应该尽快将钱转移到安全账户上。
可以新建一个账户,抢在别人之钱,将旧账户转移。

5. 如果转账写错地址,怎么办?

没有办法取消已经发布的交易。
比特币系统可以转账到不存在的账户。
地址是公钥的hash。
有些地址不是公钥的hash得到的,如digital commitment;
在验证当前交易合法性时候,不会执行(验证)本交易的输出脚本;只有在下次交易,花费这笔钱的时候,这个脚本作为上次交易的输出,才会被执行。

6. 挖矿场景,会不会存在矿工偷取别的矿工的答案,怎么确认哪个矿工先发现的nonce?

不可能出现这种情况。因为每个矿工产生的区块,nonce与块中自己的收款地址绑定在一起,别人无法冒名顶替。

7. 交易费是矿工的消费,事先不知道哪个矿工可以出块,怎么输出交易费?

交易费的多少是由谁来指定?是系统吗?
交易费的收款人地址不需要指定。

12 BTC 匿名性

Bitcoin and anonymity.
privalty.
pseudonymity.
比特性系统的账户信息,所有人都可以查询,只是无法知道账户的主人信息。
银行系统,账户信息只有银行可以查询。

比特性匿名性可倍泄露的场景:
(1)比特币账户之间通过交易关联起来,推测出是一人多账户;
(2)比特币与现实发生交易,推测出账户与实体人的关联;
比特币从事违法活动,被抓捕的案例:Silk Road/2 从事非法交易;
区块链的不可篡改性,对于隐私性的保护是灾难性的。

Hide your identity from whom?不想向谁泄露自己的身份?
向朋友隐蔽容易,向国家隐蔽难。

如果没有网络层的匿名性,那么根据网络地址可以推算出账户信息。

TOR(洋葱路由)

application经过多次转发,发送给接收者。
如何通过application layer实现匿名性?
(1)coin mixing:把不同人的币混在一起;缺点,容易卷币跑路;
(2)在线钱包,把币混合,取币时候,可能不是自己的币;
(3)交易所,天然coin mixing性质;

Zero-knowlege proof(零知识证明):

一方(证明者)向另一方(验证者)证明一个陈述是正确的,而无需透露该陈述是正确的之外的任何信息。
有争议的例子:签名,用私钥签名,证明公钥是自己的。泄露了私钥的签名。

同态隐藏,性质:

(1)如果x,y不同,那么它们的加密函数值E(x)和E(y)也不相同;
(2)hiding property:给定E(x)的值,很难反推出x的值;
(3)同态运算:给定E(x)和E(y)的值,我们可以很容易计算出某些关于x.y的加密函数值。
同态加法:通过E(x)和E(y)的值,计算出E(x+y)的值;
同态乘法:通过E(x)和E(y)的值,计算出E(xy)的值;
可以扩展到多项式;

案例:盲签方法

有没有什么方法是实现央行记账,同时不泄露信息?
应对方法:虚拟货币的编号不是由央行产生,而是由用户自己产生。采用盲签方法。
(1)用户A提供SerialNum(货币的序列码),银行在不知道SerialNum的情况下返回签名Token,减少A的存款;
问题:Token与SerialNum有什么关系?怎样实现盲签?
猜测:用E(SerialNum)签名,得出Token;
(2)用户A把SerialNum和Token给B完成交易;
(3)用户B拿着SerialNum和Token给银行验证,银行验证通过,增加B的存款;
银行在此验证的目的,是为了防止这个序号的货币被Double Spending;
(4)银行无法把A和B联系起来;
问题:银行真的无法关联A和B的交易吗?银行记录发给A的Token,当B来存钱核对一下B给的Token,不就可以关联A和B了吗?
(5)中心化;

案例:零币和零钞

专门为了匿名性产生的货币。背后的数学原理复杂,涉及密码学。
(1)零币和零钞在协议层就融合了匿名化处理,其匿名性来自密码学保证;
(2)零币系统中存在基础币和零币,通过基础币和零币的来回转换,消除就地址和新地址的关联性,其原理类似于混币服务;
(3)零钞系统使用zk-SNARKs协议,不依赖一种基础币,区块链只记录交易的存在性和矿工用来验证系统正常运行所需要关键属性的证明。区块链上既不显示交易金额,也不显示交易地址,所有交易通过零知识验证的方式进行。

13 BTC 思考

1. 区块链的hash指针

指向本地的区块链数据地址,网络中,hash指针怎么存放?
实际的hash指针,只有hash,没有指针。那么,怎么找到前节点?
全节点将所有区块存在的数据结构中,通过levelDB根据hash获取value;
由于hash是key值,所以hash自身就是指针。

2. 区块恋

两人各自保存私钥的半段,合起来才可以取钱。这样存在什么问题?
任何一方丢私钥,都会丢失私钥。
把256位截断,128位私钥的安全性破解难度降低了很多:2^256 -> 2^128

正确做法:对于多人账户,采用MultiSig多重签名的机制。

3. 分布式共识

为什么比特币系统能够绕过分布式共识中的那些不可能结论?
严格的说,比特币系统并没有取得真正意义上的共识,取得的共识随时可能被推翻,例如分叉可能被回滚。
按照分布式理论,共识一旦确定,是不可能推翻的。
理论和实际系统是有差距的。

4. 比特币的稀缺性

挖矿的收益大于挖矿的开销才是有意义的。
任何加密货币都有冷启动的问题,早期的货币价值低,参与者人少。
比特币如何应对冷启动:早期挖矿难度低,出块奖励高。

好的货币应该具备通货膨胀功能,稀缺的东西不适合做货币。早期货币积累的人,显得越来越富有,后期的人永远追不上,不是一个健康的社会。

5. 量子计算

传说中的量子计算机计算力很强大,可以破解加密算法,是否对加密算法产生威胁。
量子计算距离实用性,还有很长的时间,比特币系统有生之年可能不会遇到量子计算的攻击。
如果有风险,量子攻击首先是传统的金融业。将来会出现量子加密。
私钥可以推导出公钥,无法从公钥推导出私钥。比特币没有直接实用公钥,而是公钥的hash,具有两重的保护。
加密与取hash是不同的操作,加密的目的是为了解密,加密过程不丢失信息,可以还原原来的信息。取hash的过程是不可逆的,根据hash不能获取原来的数据。
从安全性的角度考虑,某个地址只使用一次,一旦从账户中转账,就把余额转入新的账户。

BTC 问题

  1. 如何迅速查找交易?
  2. 如何验证交易?

14 ETH 以太坊概述

被称为区块链2.0,针对比特性系统的问题进行了改进。
比如说,(1)出块时间从10分钟,降低到10几秒。
(2)挖矿使用的mining puzzle;比特币系统采用算力竞争,造成了矿机的专业化。以太坊涉及的mining puzzle对内存的要求很高,目的是在一定程度上限制了ASIC芯片的使用(ASIC resistance)。
(3)“将来”会把工作量证明(proof of work)变为权益证明(proof of stake);
(4)引入了智能合约(smart contract);

BitCoin:decntrailized currency 去中心化货币;
Ethereum: decntrailized contract 去中心化合约;

以太坊智能合约设计目的:通过科技取代司法公正。
逻辑简单清晰的合约,可以写成智能合约。

去中心化的合约,有什么好处?
违约后,通过 司法手段维权需要一定的成本。
通过技术手段,是的参与者在指定合约后,就不可能违约。

15 ETH 账户

采用基于账户的模型(account-based ledger)
例如:检测A->B (10 ETH)是否合法,只需要检测A账户是否有足够的货币,不用说明货币的来源。
这种基于账户的模式,对于double spending attack有天然防御作用。

对于replay attack(重放攻击)的防范:增加交易技术器nonce,记录账户有史以来的交易次数,作为交易信息的一部分,有签名保护;

ETH中的两类账户:

外部账户(externally owned account)

普通账户,由公钥、私钥控制;
具有:账户余额balance,
交易计数器nonce;

合约账户(smart contract account)

合约账户不可以主动发起交易,可以在被调用的时候调用别的合约。
具有:代码code(不变), 存储storage(被调用后会发生改变);

以太坊ETH的创始人Vitalik(19岁);

16 ETH 状态树

基于账户的模式,怎样证明账户余额?

设计问题:怎样描述账户状态?

  1. 能否用一个大的hash表,表示账户余额状态?
    大多数账户状态是不变的。账户数量远大约交易数量。
    如果用Merkle Tree表示所有账户的最新状态,则数据量很大。每次交易都会改变某些账户的状态,若更新生成整个所有账户的Merkle Tree,计算代价很大。这与比特币系统仅仅存储交易的Merkle Tree是不同的。
    如果采用hash表描述账户状态,为了防止篡改需要构建Merkle Tree,当由账户更新后,这个重新构建的过程是非常耗费算力的。
    采用常规的 Merkle Tree表描述所有账户,不利于快速搜索;不排序的叶节点,构成的Merkle Tree是不唯一的,算出的root hash也是不唯一的。比特币系统中,也是不排序的,但是不存在问题,因为获得记账权的节点决定了区块的最终状态。
    采用Sorted Merkle Tree表示所有账户,那么新增加账户的地址随机,会影响已有Tree的形状,需要重新计算Merkle Tree,会带来计算量很大;
    总论:采用简单的数据结构无法合理表示ETH系统账户状态。

概念:trie,retrieval(信息检索),通常是由字符串key构成的存储方式;
分叉数目:branching factor; 0~f + “\n” = 17;
key值长度等于查找次数;
ETH的地址也是公钥hash的后160Bit地址(40*4bit[0~f]),ETH的key固定长度为40;
如果用hash表存储,理论上可能会出现地址碰撞(因为截取了后半部分);
trie不会出现碰撞,只要地址不同,最后在树的分支映射不同;(??为什么??)
节点插入顺序不同,不影响最终构造出来的树的形状;
缺点:很多单子节点的节点效率很低。

Patricia tree:路径压缩后的trie;
key值分布稀疏的情况下,压缩后效率提升明显。
去中心化系统,防止账户冲突,就必须产生稀疏化的地址;

MPT: Merkle Patricia tree;
把普通指针换成hash指针;

ETH系统中采用Modified MPT
节点类型:
Extension Node:路径压缩的节点;
Branch Node:分叉节点;
Leaf Node:叶节点;
上级节点指向下级节点,不是普通指针,而是存储的hash值;

ETH系统中,账户状态发生改变后,每个全节点会新建一棵树,在新树中大部分节点与旧的节点是共享的,只有少数的节点需要新建分支。
为什么要保留历史状态?为了实现回滚roll back。

存储是经过序列化操作的;
RLP: Recursive Length Prefix,一种序列化方法;及极简主义;只支持一种类型nested array of bytes;
实现RLP比实现protal buff容易;

17 ETH 交易树和收据树

交易树和收据树可以提供Merkle Proof;
可以找到与某智能合约相关的交易;

bloom filer数据结构:
支持高效的查找某元素是否在指定集合里;
bloom filer对大集合digest计算出紧凑的向量,形成一个摘要;
方法,对集合中的元素计算hash,在向量中对应的hash位置,填1。
结论:元素在结合中,一定可以报出1,但是元素不在集合中,由可能报出1(出现hash碰撞)。
如果将集合中某元素删除,bloom filer不支持删除操作,因为可能有多个元素映射同一地址,强制设0,会误删。

在查找区块时,可以通过bloom filer过滤掉大部分不符合要求的区块,只留下少数候选区块进行进一步筛选。

ETH:transaction-driven state machine,交易驱动的状态机;
BTC的状态机是UTXO;
状态转移都是确定性的;

【代码讲解】
交易树和收据树的创建过程;

18 ETH 基于GHOST协议的共识机制

ETH提升出块速度40倍后,带来新的问题:发布区块后,区块传递到网络其它节点的耗时较大,发布越频繁,表示挖矿难度越低,在网络延时下,越难以产生共识;

State fork的处理

对状态临时性分叉的合并处理。

ETH将ophan block表示为uncle block;

最初版本的设计:
uncle block的挖掘者,获取7/83个货币;
一个合法块合理包含两个uncle block;
合法块的挖掘者获得:uncle block数/32
3 + 3个货币;
uncle block数最大为2;
这样设计有利于分叉链的及时合并;

最初版本的缺陷:
如果uncle block的数量大于3,只能被无收益的放弃;
有些矿池为了恶意竞争,故意不添加uncle block,给别人造成比自己更大的损失;

ETH的改进版本:
合法分支上的新板块,可以认定上很多级的临时分叉为uncle block;总有新出块的矿工愿意包含上游uncle block;
如果在上游不断挖出uncle block,期待被包含,怎么办?
ETH规定了uncle block获得奖励递减的机制,当代uncle block获取7/83,上一代uncle block获得6/83,依次递减5/83,…,2/83;在向前就没有奖励了。必须和当前合法出块有共同的7代祖先才行(at most seven generation);
这样鼓励出现分叉及早进行合并。

在BTC的脚本中有CHECKMULTISIG检测多重签名,有个bug,修复bug会对协议改变,如果有群体不接收改变,就会出现硬分叉Hard fork,会永久存在;

在ETH中block reward比例高于gas fee;
ETH中没有规定定期减少block reward;ETH没有人为制造稀缺性;

问题:

  1. uncle block上的交易是否需要被执行?
    不可以被执行。因为uncle block可能包含冲突的交易,本身uncle block交易信息合法,但是执行完毕parent block后,uncle block中的交易就非法了。
    合并uncle block仅检查该模块是否符合挖矿难度要求。

  2. 分叉链条上的下游分块,可不可以算是uncle block?
    这样会引来分叉攻击,使得分叉攻击的成本降低,因为分叉攻击不成功,那么也能挽回一些损失。

ETH的真实案例

Etherscan.io

19 ETH 挖矿算法

Block Chain is secured by mining.挖矿保证了区块链的安全。
bug bounty:悬赏寻找漏洞;
比特币属于天然的bug bounty,寻找bug就能获得利益,比特币系统获得了时间的检验。
比特币系统饱受争议的事实是,挖矿设备的专业化,违背了当初的设计理念。
中本聪的设计本意,“one cpu, once vote”;

比特性系统之后的加密货币,设计目标包含:ASIC resistance.
一种设计方法是增加对内存的需求,memory hard mining puzzle;

LiteCoin采用的puzzle是基于scrypt算法,对内存需求很高。
array:seed -> hash(0) -> hash(1) -> …产生伪随机数;在整个求解过程中,需要保存很大的数组,需要内存空间。有些方法仅保存奇数内存,偶数计算出来(time memory trade off)。
理想puzzle的算法要求:difficult to solve, but easy to verify。
LiteCoin的验证过程和求解过程同样耗费内存。为了照顾轻节点,LiteCoin的数组设置为128k。

ETH采用两个数据集:16M cache, 1G dataset DGA;轻节点仅保留16M cache, 矿工需要1G DAG;
16M cache array:seed -> hash(0) -> hash(1) -> …产生伪随机数;
1G DAG:从cache中按照伪随机顺序读取元素,一共读取256次后,存储大数据集合中,按照这种方式不停的读取数据放入大数据集合中;大数据集存放满了后,从发数据中按照伪随机的顺序,选择一些元素及相邻数据,64次选择128个数据,获得最终的结果;

有些观点人为:大量通用计算机参与挖矿,危险更大,因为用来大量通用服务器的集团可能产生危险的攻击。

ethash算法伪代码

生成16M的cache

def mkcache(cache_size, seed):
	o = [hash(seed)]
	for i in range(1, cache_size):
		o.append(hash(o[-1]))
	return o

生成1G DAG中的第i元素:

def calc_dataset_item(cache, i):
	cache_size = cache.size
	mix = hash(cache[i % cache_size] ^ i)
	for j in range(256):
		cache_index = get_int_from_item(mix)
		mix = make_item(mix, cache[cache_index % cache_size])
	return hash(mix)

生成大数据集:

def calc_dataset(full_size, cache):
	return [calc_dataser_item(cache, i)  for i in range(full_size)]

全节点挖矿函数:

def hashmoto_full(header, nonce, full_size, dataset):
	mix = hash(header, nonce)
	for i in range(64):
		dataset_index = get_int_from_item(mix) % full_size
		mix = make_item(mix, dataset[dataset_index])
		mix = make_item(mix, dataset[dataset_index+1])
	return hash(mix)

轻节点验证函数:

def hashmoto_light(header, nonce, full_size, dataset):
	mix = hash(header, nonce)
	for i in range(64):
		dataset_index = get_int_from_item(mix) % full_size
		mix = make_item(mix, calc_dataset_item(dataset_index))
		mix = make_item(mix, calc_dataset_item(dataset_index+1))
	return hash(mix)

挖矿过程函数:

def mine(full_size, dataset, header, target):
	nonce = random.randint(0, 2**64)
	while hashmoto_full(header, nonce, full_size, dataset) > target:
		nonce = (nonce + 1) % 2**64
	return nonce

20 ETH 挖矿难度调整

区块难度调整公式

D(H) = D0, if Hi = 0
max(D0, P(H)Hd +x*kesai2) + epsulo; otherwise;
where, D0=131072;

难度炸弹

设计初衷,当挖矿数量达到一定的程度后,采用权益证明代替劳动证明。
但是,权益证明遇到问题,目前没有很好的解决方案。
强制调整难度,推迟了权益证明的来临日期。

ETH发展的4个阶段
  1. Frontier;
  2. Homestead;
  3. Metropolis,又分为Byzantium, Constantinople;
  4. Serenity;

21 ETH 权益证明 Proof of Stake

基于劳动量证明的共识机制,普遍的批评时浪费资源,能耗大(费电)。

比特币每年总能耗 69.95TWh,相当于647W多美国家庭能耗,全世界能耗0.31%;平均每个交易1014度电,相当于34.26个美国家庭一天能耗。

ETH能耗随时间增长,每年19.78TWh;平均每个交易67Wh;

权益证明的基本思想:挖矿拼算力,本质是拼装备,不如直接拼钱。virtual mining,不直接挖矿,直接用所持有的货币数量多少进行投票。

AltCoin Infanticide:外部攻击将加密货币扼杀在摇篮中;

按照货币数量进行投票,如果想要攻击,就必须获得这个币种的51%。无法直接从外部攻击,比如装备竞赛。如果有人攻击,大量买入这个币,那么这个货币的价格就会快速上涨。

Proof of Deposit
权益证明与工作量证明不是互斥的。挖矿难度与持币数量是相关的,持币越多,挖矿难度越小,被用来降低挖矿难度的币,会锁定一段时间。
基于权益证明该怎么设计,面临很多挑战。
权益证明,投币降低难度,在没有成功出块的情况下,所投币并不会被锁定,遇到nothing at stake现象,会降低分叉攻击的投入成本。

ETH采用Casper the Friendly Finality Gadget(FFG)
每个epoch结束后,由两轮投票Prepare,Commit,每轮有2/3验证者,才算通过;
优化后将100轮的epoch变为两个50轮的epoch,没轮依次投票,分别为Prepare,Commit,连续两个epoch投票2/3才算通过。
验证者可以得到参与奖励,如果验证者有不良行为有惩罚。
如果有人攻击,一定是有一部分人两分支投票,这部分人至少1/3,一旦被发现,保证金全部销毁。

目前主流加密货币还采用工作量证明,权益证明还不成熟,没有经历过检验。

22 ETH 智能合约

智能合约是运行在区块链上的一段代码,代码的逻辑定义了合约的内容。
智能合约的账户保存了合约当前的运行状态:

  • balance:当前余额;
  • nonce:交易次数;
  • code:合约代码;
  • stage:储存,数据结构是一棵MPT;
    Solidity是智能合约的常用语言;

发起合约,就像是发起了交易。这个合约会被打包在区块中(合约状态)。合约代码不能被合约账户调用,只能被外部账户调用。

gas fee

智能合约是一个图灵完备的编程模型。
智能合约的调用出现死循环怎么办?出现Halting problem,不可解。

将问题推给发起交易的人:
智能合约中的指令要收取汽油费,由发起交易的人来支付。
EVM中不同指令消耗的汽油费时不同的。

错误处理

一次交易要么完全执行,要么完全不执行,不会执行一半。
如果在执行交易过程中出现出错,会出现全部回滚,状态就像交易没有被执行过。

如果执行到一半,gas limit被耗尽,合约回滚,已经消耗的gas fee不退费。
如果退费,则恶意节点会发动浪费资源的攻击。

嵌套调用

如果智能合约A调用智能合约B,如果B执行异常,会发生连锁回滚吗?
这取决于A调用B的方式。

智能合约在本地执行过程中,修改的都是本地的状态,只有才合约执行完毕后,发布到区块链上,本地的修改才会变为共识。

先挖矿,还是先执行合约?

先执行智能合约,产生交易,才能产生block header的内容,才能挖矿找nonce。

执行合约后,没有挖到矿,白执行合约,能得到什么补偿?

在ETH中,得不到任何补偿。
不仅如此,别人挖矿成功后,每个全节点需要在本地运行验证别人发布的区块。
只有挖到矿的矿工才有补偿,其它矿工都是“陪太子读书”。

如果不执行验证,那么本地的状态就不对了(没有同步正确状态),就无法继续参与挖矿。

如果合约执行错误,是否要发布的区块链上?

执行发布链上的交易,也要发布到区块链上,需要发布后才能扣去汽油费。

智能合约是否支持多线程?

合约代码的编程语言Solidity不支持多线程。
多线程会引起执行结果的不确定。
ETH的智能合约不能产生真正意义的随机数,只能是伪随机数。目的是执行结果必须是确定性的。
智能合约code不能通过像普通计算机语言,执行系统环境语言。智能获取区块链的信息。

23 ETH TheDAO

2016年的ETH案例,造成了ETH分裂,改写了历史。
DAO:Decentralized Autonomous Organization.去中心化的组织。
2016年5月,出现了致力于众筹投资的组织,the DAO;
1个月筹集了一个亿的以太币,众筹速度历史罕见;有人预测,3~5年后theDAO的影响力将超越以太坊本身;
如何换回投资报酬:通过拆分的方式,split DAO,建立子基金childDAO的方式;
如果一小部分人,要投资小众项目,可以拆分子基金,换算成以太币,然后重新投资;
这也是投资者取钱的唯一途径;

split DAO思想没错,但是代码实现由漏洞,被黑客攻击获取了1/3的以太币;
theDAO只是ETH上的智能合约;ETH的开发团队支持补救措施,实施回滚,但其它人不赞同;
补救措施原则,需要精确定位,只是回滚黑客盗取的那次交易;
ETH团队升级软件,加入新规则,与theDAO相关的账户交易不被认可,大多数用户升级了软件,产生了软分叉;
遗憾的是,补救软件引入了bug,有关汽油费的问题,与theDAO相关的交易不被认可,那么汽油费是否还有收取?按照之前的软件,不合法的合约是要收取gas fee的,为了防止合约发布者的恶意发布。ETH因为判断为theDAO账户交易就不收gas fee,结果导致大量的这种攻击,大量客户回滚了软件版本,软分叉版本失败。
ETH开发者使用了硬分叉,将theDAO账户钱转到新合约,新合约只有退钱功能;因为硬分叉的分钱交易没有签名,不会被旧矿工认可,所以就产生了硬分叉;
最后ETH投票,绝大多数人支持硬分叉,最终黑客没有获利。
硬分叉后,新链货币为ETH,旧链货币为ETC;有人在旧链是出于信仰,有人在旧链是出于投机;
刚分叉初期,不同链上会有重放攻击,增加chainID来防止;

24 ETH 反思

关于智能合约的反思

Is smart contract really smart?
智能合约并没有用到AI技术,有人认为称作“自动合约”更加恰当。
Smart contract is anything but smart.智能合约并不智能。

不可踹改性是一把双刃剑。
Irrevocability is a double edged sword.

思考:智能合约已经发现漏洞,但是已经发布了,该怎么办?
用黑客相同的手段,将旧合约的钱转入新的无漏洞合约。

没有什么是不可被篡改的。
Nothing is irrevocable.
一般情况下,区块链上的内容难以篡改,但是遇到重要情况,还是可以被修改的。

从语言设计上的反思。
Solidity是反自然的。fallback函数在转账时会被调用。
Is solidity the right progamming language?

编写智能合约的语言,应该具备怎样的表达特性。
现在合同对语言的约束,是在标准的模板上进行编写合同。
后面可能会有智能合约的标准模板,或者专门公司编写智能合约。

Many eyeball fallacy(错误认知,misbelief)
开源代码,可以被公众检测。
实际由精力和能力检验智能合约的人,可能很少。

去中心化与分布式不等价。
去中心化系统,一定是分布式系统。
但是分布式系统,可能是属于某个中心节点管辖。

状态机常见的应用场景:不间断的对外提供服务。
mission critical applications;
airtraffic control;
stock exchange;
space shutlle;
传统状态机系统,计算机的数量较少,运行效率低,通常比一台要慢,因为要同步数据。

25 ETH 美链(Beauty Chain)

2018年4月。
美链是一个部署在以太坊上的智能合约,有自己的代币BEC。
没有自己的区块链,代币的发行、转账都是通过调用智能合约中的函数来完成的。
可以自己定义发行规则,每个账户有多少代币也是保存在智能合约的状态变量里。
ERC20是以太坊上发行代币的一个标准,规范了所有代币的合约实现的功能和遵循的接口。
美链中有一个叫batch Tansfer的函数,它的功能是向多个接收者发送代币,然后把这些代币从调用者的账户上扣除。
利用程序漏洞,计算溢出的漏洞,使得不扣钱情况下,获取钱。

26 总结

有人认为:保险系统采用区块链,可以加快理赔速度。
观点不正确,因为理赔环节长主要是由于人为鉴定环节的时间长,而不是支付环节长。使用区块链同样绕不开人为的鉴定环节。

有人认为:区块链可以追溯食品链路,从而保证食品安全。
观点不正确,因为区块链只能防止不被篡改,但是食品链条上的输入数据是否正确,食品是否被掉包,区块链自身无法保证这些。
主要公正的三方机构,检验与签名得到保证。

有人认为:刷信用卡被骗,可以退款,区块链支付无法退款。
观点不正确。信用卡退款,是由社会制度保障的。信用卡退款其实是一笔支付。

区块链的支付速度是相比较而言的,和刷信用卡比较显得慢,和跨国转账比较,显得快。

中心化的管理方式与去中心化的管理方式各有利弊。
去中心化不是万能的。

你可能感兴趣的:(区块链,哈希算法)