区块链学习笔记

学习视频:北京大学肖臻老师《区块链技术与应用》公开课_哔哩哔哩_bilibili

                “不要被学术界的思维限制了头脑,不要被程序员的思维限制了想象力”

尚硅谷区块链全套教程完整版(深入掌握以太坊核心技术)_哔哩哔哩_bilibili

风格差异很大。

1.比特币被称为加密货币

入门指南 - 比特币

GitHub - bitcoin/bitcoin: Bitcoin Core integration/staging tree

https://explorer.btc.com/zh-CN

2.区块链上内容都是公开的,包括区块的地址,转账的金额。

3.比特币主要用到了密码学中的两个功能:1.哈希2.签名

        哈希碰撞:它是不可避免的,因为输入空间总大于输出空间。给出x,很难找到y,除非蛮力求解(brute-force)

hiding:哈希函数的计算过程是单向的,不可逆的。

哈希值的预算事先是不可预测的。

4.比特币挖矿的过程中实际就是找一个nonce,nonce跟区块的块头里的其他信息合一起作为输入,得出的哈希值要小于等于某个指定的目标预值。

5.挖矿过程中没有捷径,为了使输出值落在指定范围,只能一个一个去试。所以这个过程还可以作为工作量证明(proof of work)。

6.挖矿很难,验证很容易。

7.比特币中用的哈希函数叫作SHA-256(secure hash algorithm )以上三个性质它都是满足的。

8.在本地创立一个公私钥匙对(public key ,private key),这就是一个账户。

9.比特币中最基本的结构就是区块链,区块链就是一个一个区块组成的链表。区块链和普通的链表相比有什么区别:
        用哈希指针代替了普通指针(B block chain is a linked list using hash pointers)

        比特币没有要保存所有区块的内容,可以只保留最近的几千个区块。如果要用到以前的区块,可以向系统中其他节点要这个区块。

10.比特币中的另外一个结构是:Merkle tree。这种结构的好处:只要记住根哈希值,就能检测出对树中任何部位的修改。

11.merkle tree 的作用:①提供merkle proof

        比特币中的节点分为两类:全节点(保存整个区块的内容,即块头块身都有,有交易的具体信息)和轻节点(例如手机上的比特币钱包)(只有块头)

12.比特币中不需要做不存在证明。

13.数字货币和纸质货币区别是可以复制,叫作双花攻击 即double spending attack。

14.去中心化货币要解决两个问题:①数字货币的发行②怎么验证交易的有效性,防止double spending attack()。

        ①比特币的发行是由挖矿决定的

        ②依靠区块链的数据结构
比特币的发行者A拥有铸币权(createcoin
) 假如发行10个比特币 A(10)分别给B和C各五个 → B(5)C(5) 该交易需要有A的签名,证明经A同意。(designed by A)同时还要说明花掉的10个比特币从哪来的。

15.比特币系统中每个交易都包含输入和输出两部分。输入部分要说明币的来源,输出部分要给出收款人公钥的哈希。

16.比特币系统里收款的地址是通过公钥推算出来的。比如B的地址就是B的公钥取哈希然后经过一些转换得到的。

17.A需要知道B的地址,B需要知道A的什么信息吗?B其实也要知道A的公钥,这代表A的身份。不仅是B,所有节点都需要知道A的公钥。而签名是用私钥签名公钥验证(注意不要跟前面知识弄混了,加密是用接收人的公钥加密私钥解密),所以区块链上每个节点都要独立验证。

那如何才能知道A的公钥?实际上交易里就包含了。输入时不仅要输入币的来源,还要输入公钥。那就存在了安全漏洞,假如B的同伙伪造了这次交易呢?其实铸币交易的输出就有A的公钥的哈希,所以第二个交易里A的公钥要跟前面哈希对的上。

在比特币系统当中,前面这些验证过程,是通过执行脚本来实现的。每个交易的输入提一段脚本,包括给出公钥的过程,公钥也是在输入的脚本里指定的。每个交易的输出也是一段脚本,验证其的合法性,就需要把当前交易的输入脚本跟前面交易(提供币来源的交易)的输出脚本拼在一起,然后看看能不能顺利执行,如果能执行说明是合法的。

18.块头包含的是区块的宏观信息,比如:用的是比特币哪个版本(version)的协议,区块链当中指向前一个区块的指针(hash of previous block header),整颗merkle tree 的根哈希值(merkle root hash),还有两个域是跟挖矿相关的,一个是挖矿的难度目标预值(target),另一个是随机数nonce。

19.全节点是保存区块链所有的信息的,验证每一个交易,所以全节点又叫fully validating node。轻节点只保存block header的信息,一般来说轻节点没法独立验证交易的合法性。

20.关于分布式系统有很多不可能结论(impossibility result),其中最著名的是FLP。这三个字母是三个专家的名字缩写,他们的结论是:在一个异步的(asynchronous)系统里,(网络传输迟延没有上限就叫异步系统),即使只有一个成员是有问题的(faulty),也不可能取得共识。

21.比特币刚上线的时候,每一个发布的区块可以产生50BTC(BTC就是比特币的符号)。协议中规定,21万个区块以后,初块奖励就要减半,就变成了25BTC。再过21万个区块,又要减半。

22.比特币争夺记账权的过程叫作挖矿(mining),比特币被称为数字黄金(digital gold),争夺记账权的节点被称为矿工(miner)。

23.区块链是去中心化的账本,比特币使用的是基于交易的这种账本模式(transaction【交易】-based ledger【账本】)。系统当中并不会显示每个账户有多少钱。

24.比特币系统的全节点要维护一个叫UTXO(unspent transaction output)(还没有被花出去的交易的输出)的数据结构。区块链上有很多交易,有些交易的输出可能已经被花掉,有些还没有被花掉。所有没有被花掉的输出的集合就叫做UTXO。

25.每个交易可以有多个输入,也可以有多个输出,所有输入金额之和要等于输出金额之和。剩余的作为手续费。

26.21万个区块大概要挖多长时间呢?大约是4年。比特币系统设计的平均出块时间是10分钟,就是整个系统平均10分钟会产生一个新的区块。

27.挖矿的难度:每隔2016个区块要调整挖矿的难度,保持出块时间在10分钟左右

28.nonce只有2的32次方个可能的取值。按照比特币现在的挖矿情况来说,很可能把2的32次方个取值都验了一遍也找不到合适的。修改merkle tree的根哈希值:铸币交易没有输入,它有一个coinbase,可以写入任何的内容。

29.所以真正挖矿的时候只有两层循环,外层循环调整coinbase域的extra nonce。算出block header里的根哈希值之后,内层循环再调整header里的nonce。

30.挖矿过程每次尝试一个nonce可以看作是一个Bernoulli trial(伯努利实验)。每一个随机的伯努利实验就构成了一个伯努利过程。它的一个性质是:无记忆性。

31.出块奖励是系统中产生新的比特币的唯一途径。产生的比特币构成的一个几何序列。(2100万)

32.比特币求解的puzzle,除了比拼算力之外,没有其他实际意义。比特币的稀缺性是人为造成的。
虽然挖矿求解puzzle本身没有实际意义,但是挖矿的过程对于维护比特币系统的安全性是至关重要的。挖矿提供一种凭借算力投票的有效手段,只要大部分算力是掌握在诚实的节点手里,系统的安全性就能够得到保证。

33.比特币协议当中,缺省(系统默认)的是要等六个confirmation。有了六个confirmation,才认定M→A的交易是不可篡改的。

34.区块链是不可篡改的账本,那是不是意味着凡是写入区块链中的内容就永远改不了呢?经上述分析可以看出,这种分析只是一种概率上的保证。刚刚写入区块链的内容,还是比较容易被改动的。经过一段等待时间之后,或者后面几个区块被确认之后,被篡改的概率就大幅度下降(指数级别的下降)。

35.比特币协议中规定,每个区块的大小是有限制的,最多不能超过一兆字节。

36.比特币工作在应用层(application layer:Bitcoin block chain),它的底层是一个P2P网络。

37.要加入P2P网络首先得知道至少有一个种子节点,然后你要跟种子节点联系,它会告诉你它所知道的网络中的其他节点,节点之间是通过TCP通信的,这样有利于穿透防火墙。

38.比特币网络的设计原则是:简单、鲁棒,而不是高效。每个节点维护一个零度节点的集合,消息传播在网络中采取flooding的方式。节点第一次听到某个消息的时候,把它传播给去他所有的零度节点,同时记录一下这个消息我已经收到过了。下次再收到这个消息的时候,就不用转发给零度节点了。
零度节点的选取是随机的,没有考虑底层的拓扑结构。比如一个在加利福尼亚的节点,它选的零度节点可能是在阿根廷的。这样设计的好处是增强鲁棒性,它没有考虑底层的拓扑结构,但是牺牲的是效率,你向身边的人转账和向美国的人转账速度是差不多的。

39.出块时间越来越短,会有什么问题吗?
比如说不到一秒就出一个区块,区块在网络上传播的时间可能需要几十秒,底层的比特币网络可能需要几十秒才能让其他节点都收到。别的节点没有收到这个区块之前还是继续沿着已有的区块链往下扩展。如果有两个节点同时都发布一个区块,这个时候就会出现分岔。

出块时间如果越来越短的话,这种分岔会成为常态,而且不仅会出现二分岔,可能会出现很多的分岔。比如10个区块同时被挖出来,系统可能会出现10分岔。

分岔如果过多,对于系统达成共识是没有好处的,而且危害了系统的安全性。

40.比特币协议中规定,每2016个区块后就要调整目标预值,这大概是每两个星期调整一次。

具体的调整公式:target =target×(actual time/expected time)。actual time指产生2016个区块实际花费的时间,expected time指产生2016个区块应用的时间,即2016×10min。

如果实际花费时间超过了两周,即平均出块时间超过了10min。那么这时候挖矿难度要调的低一点,应该让出块更容易。因此该公式算出来的target会变大,则难度会下降。

目标预值增大最多只能增大4倍。

41.挖矿的设备:挖矿设备演化趋势是越来越趋于专业化,最早的时候用的是普通的CPU挖矿。

第二代设备:GPU。

现在更多用ASIC芯片挖矿,这是专门为了挖矿而设计的芯片,上面没有多余的电动逻辑,这个芯片除了挖矿什么事都干不了,而且为某一种加密货币设计的ASIC芯片,只能挖这一种加密货币。除非这两个加密货币用同一个mining puzzle。

42.挖矿机的变化趋势,是从通用变得越来越专用,CPU是通用计算,GPU是通用并行计算,ASIC是专用计算。

43.挖矿的另一个趋势是大型矿池的出现。

44.比特币使用的脚本语言是非常简单的,唯一能访问的内存空间就是一个堆栈。

45.前面交易的输出脚本放在后面,后面交易的输入脚本放在前面。在早期的比特币实践中,这两个脚本是拼接在一起,从头到尾执行一遍。后来出于安全因素的考虑,这两个脚本改为分别执行。首先执行输入脚本,如果没有出错就再执行输出脚本。如果能顺利执行,最后栈顶的结果为非零值,也就是true,那么验证通过,这个交易就是合法的。如果执行过程中出现任何错误,这个交易就是非法的。

46.输出脚本的几种形式:

一种最简单的形式就是P2PK(pay to public key)。输出脚本里直接给出收款人的公钥。

第二种形式P2PKH(pay to public key hash),跟第一种区别是输出脚本里没有直接给出收款人的公钥,给出的是公钥的哈希。P2PKH是最常用的脚本信息。

最后一种也是最复杂的一种脚本形式,是Pay to Script Hash。这种形式的输出脚本给出的不是收款人的公钥的哈希,而是收款人提供的一个脚本的哈希,这个脚本叫redeemscript,赎回脚本。

47.比特币中check multisig的实现,有一个bug,执行的时候会从堆栈上多弹出一个元素,这个就是它的代码实现的一个bug。

48.区块链由一条链变为两条链就叫分叉。分叉可能是多种原因造成的,比如挖矿的时候,两个节点差不多同一个时候挖到了矿,就会出现一个临时性的分叉,我们把这个分叉叫作state fork,是由于对比特币区块链当前的状态有意见分歧而导致的分叉。

49.根据对协议修改的内容的不同,我们又可以进一步分成硬分叉和软分叉。出现硬分叉的情况:如果对比特币协议增加一些新的特性,扩展一些新的功能,这些时候那些没有升级软件的这些旧的节点,它是不认可这些新特性的,认为这些特性是非法的,这就属于对比特币协议内容产生了意见分歧,所以会导致分叉。

50.软分叉是临时性的,硬分叉是永久性的。

51.软分叉出现的情况是什么?如果对比特币协议加一些限制,加入限制之后原来合法的交易或区块在新的协议当中有可能变的不是合法了,这就引起软分叉。

52.一个轻节点,没有维护整个区块的内容,只知道block header。想要证明某个账户上有多少钱,这个目前在比特币系统中是证不出来的。

53.比特币历史上比较著名的软分叉的例子是pay to script hash。P2SH这个功能在最初的比特币版本里是没有的,它是后来通过软分叉的功能给加进去的。

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

55.如果账户的私钥丢失了,该怎么办?

私钥丢失之后是没有办法的。该账户上的钱就变成了死钱,永远取不出来了。在去中心化的系统里,是没有人可以给你重置密码的。

56.如果私钥泄露了怎么办?

我们能做的就是在第一时间抢在别人之前把自己账户上的钱转到一个安全的账户上。

57.网络层的匿名性是比较好解决的。区块链是个新生事物,但网络层的匿名性学术界已经有了很好的方案:多路径转发。跟洋葱路由(TOR)是一样的原理。即消息不是由发出者直接发送给接收者,中间要经过很多次转发。中间的每一个节点,只知道它的上一个节点是谁,但并不知道最早发出消息的人是谁。

58.应用层怎么提高匿名性?
把不同人的币混在一起(coin mixing),即把你的身份跟别人的身份混在一起,让别人分不清楚谁是谁。不光是区块链,在其他各个需要匿名的领域都能用到。有一些专门做coin mixing的网站,提供一定的服务收取一定的服务费。所有想做coin mixing的人把币发给网站,网站内部进行一些重组,然后你再把币取回来,这时取出的币就不是发布到网站上的币了,它是随机抽取一些币给你。

59.零知识证明:零知识证明是指一方(证明者)向另一方(验证者)证明一个陈述是正确的,而无需透露除该陈述是正确的外的任何信息。

60.同态隐藏:零知识证明的数学基础是同态隐藏。

第一个性质说明加密函数值E不会出现碰撞,这跟哈希函数有所不同,哈希函数是可能出现碰撞的。这个性质反过来说明如果E(x)和E(y)是相等的,那么x、y也是相等的。

第二个性质说明加密函数是不可逆的,知道加密后的值,没办法推出加密前的值。

第三个性质是最重要的,叫作同态运算。它说的是对加密之后的函数值进行某些代数运算,等价于对这些输入直接进行代数运算然后再加密。
同态加法:加密值的和等于和的加密。
同态乘法:加密值的乘积等于积的加密。

61.分布式共识:

从理论上实现分布式系统的共识是不可能的,但实际当中又怎么变的可能了呢?为什么比特币系统能够绕过分布式共识中的那些不可能结论?严格来说,比特币并没有取得真正意义上的共识,因为取得的共识随时有可能被推翻,比如出现了分叉攻击。你以为已经取得了一个共识,分叉攻击后系统会回滚到前一个状态,从理论上说甚至有可能回滚到创世纪块。

按照分布式系统理论的要求,共识一旦达成之后,就不应该再改了,所以从这方面来说比特币并没有绕过分布式系统那些不可能的结论,因为它并没有达到真正意义上的共识。这说明理论和实际往往是有区别的。很多理论上的不可能结论对于实际当中是并不适用的,因为这种不可能结论只是对某种特定的模型下是不可能的,实际当中把模型稍微改一改不可能结论就不成立了。

62.实际上,比特币这种总量恒定的性质是不适合用来做货币的。一些新型的货币甚至要自带通胀的功能,每年要把货币的通行量提高一定的比例。因为稀缺的东西是不适合用来做货币的,通货膨胀会导致钱变得更不值钱了,但一个好的货币是要有通货膨胀的功能的。

63.比特币当中用的非对称加密体系,从私钥是可以推导出公钥的。所以只要把私钥保管好,公钥其实丢了也没有关系。

64.ETH-区块链2.0

以太坊出块时间更少,以太坊的miningpuzzle对内存的要求很高,叫memoryhardminingpuzzle。这种叫ASICresistance。以后可能用权益证明proofofstake代替proofofwork。可能就不需要挖矿了。

智能合约:如果货币能够去中心化,那还有什么可以去中心化?以太坊的出现增加了一个去中心化的合约的知识。用技术手段,把司法手段给取代了?通过区块链的不可篡改性,来保证合同的完整性。

65.ETH账户

1、比特币是花钱的时候,说明你钱的来源。

2、比特币在使用时,必须一次性花掉。

问题在于:比特币没有显示的维护基于账户交易的概念。

以太坊系统是基于账户的模型account-basedledger

不用说明来源,也不需要一个找零的地址。

以太坊不用管币的来源,直接从余额上扣钱,所以对doublespending有天然的防范。你的余额是全节点维护的状态树。

重放攻击-replayattack:B把A->B的交易重放一遍。收钱的人不诚实。加一个计数器,nonce,在转账时,加入进去,并受发布者签名的保护,这个nonce的值,别人改不了。

66.以太坊有2类账户:

1、外部账户:externallyownedaccount有账户余额balance;nonce【实际是计数器】

2、合约账户:smartcontractaccount有balance,有nonce,但是合约账户不能主动地发起一个交易。必须由外部账户调动合约账户,不能由合约账户直接发起交易。

67.以太坊的方法:MTP数据结构

68.每次出现一个区块,都需要新建一个MTP。ETH,中的状态树是一个大的MTP,包含一个个小的MTP,类似这个图,后一个节点,通过逐层merkle,来保存历史信息。通过保存历史信息,可以对信息进行回滚。以太坊有智能合约,不保存以前的状态,智能合约执行完之后,你想再推算出前面的状态是不可能的,所以必须要保存历史状态。

69.value是怎么存储在状态树中?

RLP:recursivelengthprefix是一种做序列化的方法,特点是极简主义。protocolbuffer做序列化的库

70.ETH-交易树,收据树,状态树

1、ETH每次发布一个区块的时候,每个区块里面的交易会组成一个merkletree和BTC中情况类似,每次交易执行完之后,会形成一个收据,记录这个交易的相关信息,增加收据树,是考虑到ETH的智能合约比较复杂,有利于我们快速地查询执行的相关信息。

2、ETH中的交易树,用得是MTP,用同样的数据结构,代码统一,方便管理。而且支持查找操作。对于状态树来说,查找的key就是这个交易的地址。对于交易树和收据树来说,key就是交易在发布的区块的序号。交易树和收据树,只把当前交易的区块的信息组织起来。而状态树是系统中所有账户。多个区块的状态树,是共享节点的。

3、为了方便查找符合条件的交易信息,ETH中引入了bloomfilter的数据结构。

查找时,只要将查找的元素取哈希,找到映射的摘要位置。如果该位置为0,则表示该元素一定不在集合中,如果为1,则表示可能会在集合中。bloomfilter不会falsenegative,即不会漏报。有些复杂的bloomfilter不止应用一个哈希函数,通过多个哈希函数来增强元素在集合的可能性。另外bloomfilter不支持删除操作。

71.ETH可以看做是一个交易驱动的状态机transaction-drivenstatemachine。BTC的状态是UTXO。也是一个交易驱动的状态机。状态转移都是确定性的。

72.ETH15s的出块时间,会使得临时性的分叉成为常态。

73.叔父区块规定,必须在7代以内和当前区块有共同的主线。叔父区块是得不到汽油费。

74.ETH不执行叔父区块里面的交易,甚至也不检查叔父区块里面交易的合法性。只检查叔父区块是否符合挖矿难度要求的【header】。

75.ASICresistance:增加这个puzzle对内存访问的需求。

开设一个很大的数组,然后按照顺序填充一些伪随机数,假设,第一个是一个种子节点,我们将种子节点,通过加密,算出一个值,放在数组的第一个位置,然后后面每一个位置,都是前一个位置,取哈希得到的。这种数组的填充特点,前后依赖关系的,都是从第一个数算出来的。然后求解puzzle的时候,按照伪随机的顺序,从数组当中读取一些数,每次读取的位置也是和前一个数相关的。有些矿工只保存部分位置的元素,比如,只保存奇数位置的元素。这种我们将其叫做timememorytrade-off。

76.ETH很早就计划从工作量证明转为权益证明。PoW---->PoS。

77.有些人认为让专门的ASIC参与挖矿才是安全的:你需要投入大量的资金投入专门的矿机,而且这个矿机除了挖矿,干不了其他事。所以发动这种攻击的成本是非常巨大的。一旦攻击成功表示BTC的安全性大幅度降低,BTC的价格就会大幅度缩水,这样投资就收不回本了。如果不这样这样就不需要为了挖矿投入专门的设备,发动攻击的成本就会大幅度下降了。通过云服务租用这些服务器,来完成这个攻击。

78.ETH-难度调整

无论是上调还是减少,调整的力度为父区块的难度的2048分之一。难度有个下限-99,表示一次性下调的难度最大为99/2048。

79.工作量证明-------->权益证明会形成硬分叉,为了避免这种情况,ETH在设置公式的时候,设置了难度炸弹。等到难度炸弹威力发挥出来的时候,这时候就是ETH从工作量证明,转换为权益证明了。基于权益性能的共识机制,设置起来过于复杂,这样导致转成权益证明的时间点,被一再推迟。现在就是即便难度增加了,但也没办法,只能继续挖。所以又减少了3000000的区号。

80.权益证明的思想:挖矿是需要投资的,既然这样,不如直接比拼投入的资金。也就是virtualmining。按照持有货币的数量,投票来挖矿。这种有个好处,就是省去了挖矿带来的能耗问题。基于工作量证明的共识系统,从某种意义上来说,维护这个区块链安全的资源,并不是一个闭环。(因为mining的equipment是从法币过来的)虽然加密货币的总市值非常高,但对比世界经济的总量,它还是微乎其微的。

81.混合模型:两边下注问题,会增大分叉攻击的风险。

82.solidity语言哈希表不支持遍历。

83.外部账户如何调用智能合约:

创建一个交易,接收地址为智能合约的地址,data域要填写调用的函数及其参数的编码值。

84.一个合约调用另一个合约的函数

1、直接调用

2、使用address类型的call函数

与上种方法不同在于错误的处理方式不同。如果是上一种方法:如果A在执行过程中出现异常,会导致B这个合约也出现异常。address中,如果被调用的函数发生异常,会返回一个call()异常,但发起调用的函数并不会抛出异常。

3、代理调用delegatecall

使用方法与call相同,只是不能使用.value()

区别在于是否切换上下文,delegatecall函数的存储和余额都取自当前合约。

85.fallback():该函数主要是防止A向B转账,但没有在data域中说明要调用哪个函数或说明的要调用函数不存在,此时调用fallback()函数。

如果没有fallback(),在发生之前的情况后,就会直接抛出异常。

86.智能合约代码写完后,要编译成bytecode。

87.创建合约:

外部账户发起一个转账交易到0x0的地址,转账金额是0,但是要支付汽油费,合约代码放到data域里。

88.智能合约运行在EVM上。

89.以太坊是一个交易驱动的状态机。

90.EVM:通过增加一层虚拟机,给智能合约提供一个一致性的运行平台。EVM的寻址空间为256位。不存在一个代码对任意给定的一个输入程序,判断它会停机。所以ETH引入了汽油费的机制,把问题推给了发起交易的人。

91.当一个全节点收到一个对智能合约的调用的时候,根据这个合约中的price,gaslimit算出可能的最大汽油费,一次性地将这个费用,从发起交易的账户上扣除,然后根据实际执行的情况,算出实际划掉的汽油费。多退少补。取哈希就是消耗的汽油费就比较贵了。如果执行到一半的时候,汽油费不够了,那么这次的交易就会回滚,但花掉的汽油费就不会退了。为了防止有人通过发布一些计算量较大的合约,给得汽油费又不够,浪费矿工的资源。

92.区块blockheader里面的gaslimit指的是区块内部所有交易实际能够消耗的汽油的上限。类比BTC只能发布1M的区块。这里ETH因为智能合约的原因,无法通过大小进行限制,所以通过汽油费进行限制。

93.每个矿工在发布区块的时候,矿工可以再上一个区块的gaslimit基础上,上调或者下调1/1024。

94.执行错误的交易,也要发布到交易上,否则扣不掉汽油费。每个交易执行完后会生成一个收据树。

95.solidity不支持多线程。

96.transfer和send这两个是转账的函数,transfer会导致连锁性回滚。send会返回一个false,不会导致连锁性回滚。call本来是调用函数,也可以用于转账。但call会把剩下所有的汽油都发过去了。

97.重入攻击

98.TheDAO:2016年出现了一个众筹的投资资金:TheDAO本质是运行在ETH上的智能合约。你把ETH发给智能合约换成TheDAO的代币。想要投资哪个项目,你手中的代币越多,你所拥有的权重就越大。如果有了收益则按照智能合约的规章制度来分配利益。2016年5月出现,在当时被称为伟大的尝试。1个月筹集到了1.5亿美元的ETH。遗憾的是TheDAO只存在3个月。问题在于你怎么换回投资的资金:splitDAO,建立子资金的方法(childDAO):这个设计的理念是允许一部分人从TheDAO里面拆分出去,来换回对应的ETH,然后他们就能投他们想投的项目。极端情况,单个人投资一个子资金。这是投资者收回收益的唯一方式。拆分有7的讨论期,28天的锁定期。问题出现在splitDAO的实现上。黑客通过重入攻击调取了5000万的ETH。ETH社区对此进行激烈的讨论,一派认为要回滚交易。成立的子资金有28的锁定期,可以有补救措施。另一派认为不需要什么补救措施,黑客的行为并没有违法。codeinlaw。只是上面的智能合约上有个安全漏洞,如果每个漏洞你都回滚,那么你怎么说你是去中心化的开放合约。支持的人认为TheDAO占到ETH的1/3了。TheDAO is toobigtoofail。

1、ETH发布了一个软件升级,凡是跟TheDAO基金上账户做相关的,不允许做任何交易。大多数ETH矿工都升级了。软分叉,旧矿工挖出的区块,新矿工可能不认可。新矿工挖出的区块,旧矿工一定是认可的。可惜的升级后的软件有个bug,在于汽油费方面【按我们想应该要收去汽油费的,但是ETH恰恰就是在这里没有收取汽油费。最后导致网上有大量的这种攻击,导致矿工受不了了纷纷回滚了这次的升级,于是软分叉就失败了,软分叉的方案失败之后,剩下的时间就不多了】。2、ETH升级了一个硬的分叉,将TheDAO上的资金,强行转到另外一个新的智能合约上面去。这个新的智能合约只有一个功能,就是退钱。把代币退还成ETH。这个就是硬分叉了。用软件升级的方法,强行记账,不管TheDAO上的用户同意不同意。就好比法院的强制执行,不用什么合法不合法的签名。所以这是个硬分叉。

99.ETH通过智能合约,通过ETH权重投票,结果大部分人支持硬分叉,大部分矿工也同意升级了。大家等着挖出的192万个区块的历史性时刻。黑客盗取ETH的行为,最终还是没有获利。其实这个故事没有结束,当初反对的人,并没有投票结果就同意这个处理方案。两点理由:1、投票是通过2个智能合约锁仓,结果出来后再退回来。大多数人并没有参与其中。2、大多数人的意见一定是正确的吗?硬分叉过后,旧的那条链并没有消失,只是算力变成了原来的1/10。好处是挖矿难度也下降了,主要是竞争没那么激烈了。现在不到2%。硬分叉之后,新的链继承了这个符号ETH,旧链变成了ETC。有些事处于投机目的,也有一些是出于信仰。结果ETC一直存在到现在。后来增加了一个chainID,就正式分裂了。

100.Nothingisirrevocable!不要迷信区块链的不可篡改。毕竟代码是死的,人是活的。老师用美国第18宪法修正案来举例。【著名的禁酒令】opencontainerroad。一般情况下,区块链上的内容是改不了的,但遇到重大事件,改还是能改得了的。

101.solidity这个语言的特性是反自然的。我给你转账的操作等于是隐性地调用了你的fallback,结果你还能过来调用我。

102.去中心化:寻找一个全新的管理模式。很多人认为又回到了一个中心化的管理结构。

whatdoesdecentralizationmean?最后硬分叉能够成功,是因为绝大部分矿工升级了软件,执行了硬分叉。小部分沿着原来的旧链,继续挖,ETH团队也没办法强迫他们转过来。分叉恰恰是去中心化的体现,你可以选择放弃,但是没办法选择分叉。用户不满意,就有选择分叉的权利。

103.decentralized!=distributed去中心化,不等于分布式。但分布式是去中心化的前提。

104.美链溢出漏洞。solidity对溢出的检测有个safemath的库。

105.solidity在线编译环境:Remix - Ethereum IDE

106.rinkeby水龙头:https://rinkebyfaucet.com/

 107.rinkeby前端页面:https://rinkeby.etherscan.io/

 108.以太坊黄皮书:GitHub - ethereum/yellowpaper: The "Yellow Paper": Ethereum's formal specification

pdf:https://ethereum.github.io/yellowpaper/paper.pdf

中文版:ethereum_yellowpaper/ethereum_yellow_paper_cn.pdf at master · yuange1024/ethereum_yellowpaper · GitHub

 109.撤回交易:发出的交易想要撤回,立即发布一笔相同跟要撤销交易相同的nonce,设置高手续费。(不一定保证成功,metaMask有提供该功能。)

110:go-ethereum:GitHub - ethereum/go-ethereum: Official Go implementation of the Ethereum protocol

文档:Go Ethereum

git clone https://github.com/ethereum/go-ethereum.git

make geth

./build/bin/geth --datadir ./data

--datadir ./data 数据目录

--syncmode=snap 快速同步

 --rinkeby 启动rinkeby测试网络

111:初始化私链

vim genesis.json 
//{
//    "config": {
//        "chainId": 55
//    },
//    "difficulty": "2000",
//    "gasLimit": "100000",
//    "alloc": {
//        "5D8b96b45e18930cEE33E0ef442090Ab29d33Ef1": {"balance": "1000000000000000000"}
//    }
//}

因版本原因,上面的配置文件是错误的,会导致转账失败。使用下面的配置文件初始化私链。

参考链接:以太坊私有链转账时报错eth.sendTransaction | 登链社区 | 技术问答

{
    "config": {
        "chainId": 55,
        "homesteadBlock": 0,
        "eip150Block": 0,
        "eip155Block": 0,
        "eip158Block": 0,
        "byzantiumBlock": 0,
        "constantinopleBlock": 0,
        "petersburgBlock": 0,
        "istanbulBlock": 0
    },
    "alloc": {},
    "coinbase": "0x0000000000000000000000000000000000000000",
    "difficulty": "0x2000",
    "extraData": "",
    "gasLimit": "0x2fefd8",
    "nonce": "0x0000000000000042",
    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp": "0x00"
}
 ./../go-ethereum/build/bin/geth --datadir ./ init genesis.json

运行私链:

./../go-ethereum/build/bin/geth --datadir ./ --networkid 55 

启动控制台:

./../go-ethereum/build/bin/geth --datadir ./ --networkid 55 console

控制台命令:web3、admin、eth、personal、txpool、miner

配置文件中预留的账户不在eth.accounts中显示。该命令显示的是keystore中的账户。

查询账户余额:

 eth.getBalance("0x5D8b96b45e18930cEE33E0ef442090Ab29d33Ef1")

转换为ether展示:

web3.fromWei(eth.getBalance("0x5D8b96b45e18930cEE33E0ef442090Ab29d33Ef1"),'ether')

查看区块高度:

eth.blockNumber

创建新账户:

 personal.newAccount()

转账:

eth.sendTransaction({from:"0x339fb4d4377a1b61b81e7be8be00a7cd5b0b998a",to:"0x5D8b96b45e18930cEE33E0ef442090Ab29d33Ef1",value:10000})

解锁账户:

personal.unlockAccount("")

视频教程上转账前需解锁,自己用的时候没要求。

查看矿工账户:

eth.coinbase

挖矿获取eth:

miner.start(1)

没有交易也能发布区块?

启动时将日志重定向:

 ./../go-ethereum/build/bin/geth --datadir ./ --networkid 55 console 2>output.log

帮助文档:以太坊 Homestead 文档 — Ethereum Homestead 0.1 documentation

112:30303端口是节点发现端口,需要启动rpc服务才能使metaMask成功链接。

版本原因,先启动服务再开启rpc服务。修改metaMask中localhost的端口,成功连接。

admin.startRpc()

参考链接:以太坊网络重启并开启rpc_blockchain_yhj的博客-CSDN博客_以太坊rpc

113.启动权益证明poa的私链。不需要提前构建,会自动构建一条私链。

./../go-ethereum/build/bin/geth --datadir ./  --dev  console

114.获取交易信息

eth.getTransaction("0x55171903eb86d38c1779bd71fcb4b85f8fd5365e9f61c6fc214e282938e839e5")

115.以太坊的账户类型

外部账户(EOA):包含以太币余额,可发送交易,由用户私钥控制,没有关联代码。

合约账户:有余额,有关联代码,由代码控制,可被用户或其他合约调用,有自己操作的存储空间,可以调用其他合约。

116.以太坊交易:签名的数据包,由普通账户发送,包含消息的接收放地址、发送方签名、金额、数据、start gas(gas limit)、gas price

117.消息:合约可以向其他合约发送消息,消息是不会被序列化的虚拟对象,只存在于以太坊的执行环境(EVM)中。可以看作函数调用。包含消息的发送和接收方,金额、数据和start gas。

118.合约:可以读写自己的内部存储(32字节的key-value数据库),可向其他合约发送消息,依次触发执行。一旦合约运行结束,并且由他发送消息触发的所有子执行结束,EVM就会终止运行,直到下次被唤醒。

119:交易的本质:交易是由外部拥有的账户发起的签名消息,由以太坊网络传输,并被序列化后记录在以太坊区块链上。

交易是唯一可以触发状态更改或导致合约在EVM中执行的事物。

以太坊是一个全局单例状态机,交易是唯一可以改变其状态的东西。

合约不是自己运行的,以太坊也不会“在后台”运行,以太坊上的一切变化都始于交易。

120.交易的数据结构

交易是包含以下数据的序列化二进制消息:

nonce:由发起人EOA发出的序列号,用于防止交易的重播

gas price:交易发起人愿意支付的gas单价(wei)。

start gas:交易发起人愿意支付的最大gas。

to:目的以太坊地址。

value:要发送到目的地的以太数量。

data:可变长度二进制数据负载(payload)。

v,r,s:发起人EOA的ECDSA签名的三个组成部分。

交易消息的结构使用递归长度前缀(RLP)编码方案进行序列化,该方案专为在以太坊中准确和字节完美的数据序列化而创建。

nonce强制来自任何地址的交易按顺序处理,没有间隔,无论节点接收他们的顺序如何。

121.以太坊是一个允许操作并发的系统,但是强制执行单例状态。

122.发起交易时设置的gas limit并不是要支付的gas数量,而只是给定了一个上限,相当于押金。实际支付的是执行过程中消耗的gas,执行完之后剩余的gas会退回给发送人。

123.查看交易所需gas:eth.estimateGas()

eth.estimateGas({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei('1','ether')})

eth.estimateGas({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei('1','ether'),data:'0x1111'})

124.交易的主要负载是data和value两个字段,有没有data或者value或者两者都没有,都是合法交易。

125.发送给合约的数据有效负载是32字节的十六进制序列化编码。

函数选择器:函数原型的Keccak256哈希的前四个字节,这允许EVM明确的识别将要调用的函数。

函数参数:根据EVM定义的各种基本类型的规则进行编码。

web3.sha3("withdraw(uint)"),该方法封装了Keccak256。

126.以太坊虚拟机EVM是智能合约的运行环境。

作为区块验证协议的一部分,参与网络的每个节点都会运行EVM,他们会检查正在验证的块中列出的交易并运行由EVM中交易触发的代码。

EVM不仅是沙盒封装,而且是完全隔离的,在EVM中运行的代码是无法访问网络、文件系统和其他线程的,甚至智能合约的访问也会受限。

合约以字节码的格式存在于区块链上。

合约通常由solidity语言编写,通过EVM编译器编译为字节码,最终通过客户端上载部署到区块链网络中。

127.外部账户和合约账户公用EVM的地址空间。每个账户在EVM中都有一个键值对形式的持久化存储,其中key和value的长度都是256位,称之为存储空间。

128.代码每执行一步,扣掉一部分gas,逐渐扣除。无论执行到哪一步,一旦gas被耗尽,将会触发out-of-gas异常,当前调用帧所做的所有状态都将被回滚。

129.storage:每个用户都有一块持久化的存储空间,成为storage,可以理解为合约的数据库。永久存储在区块链中。由于会永久保存合约状态变量,所以读写的gas开销也最大。

不可预估大小,所以无法遍历。

memory:每次消息调用,合约会临时获取一块干净的内存空间。生命周期仅为整个方法的执行期间,函数调用后回收。因为是临时保存,gas消耗小。

stack:EVM不是基于寄存器的,而是基于栈的。因此所有的计算都在一个被称为栈的区域执行。存放部分局部值类型变量,几乎免费使用,但是有数量限制。

130.合约可以访问当前区块的相关属性,如块高度和时间戳。

131.消息调用:合约可以决定在其内部的消息调用中,对于剩余的gas,应发送和保留多少。

如果内部消息调用发生了异常,这将由一个被压入栈顶的错误值所指明,此时只有与该内部消息调用一起发送的gas会被消耗。(剩余的是否会还给合约账户?

132.委托调用(delegatecall):目标地址的代码将在发起调用合约的上下文中执行,并且msg.sender和msg.value不变。由此可以实现公共库,放到指定的合约存储上。

133.合约内部也可以创建合约,但是只保存在内存中,用完就会销毁。

134.合约代码从区块链上移除的唯一方式是合约在合约地址上执行自毁操作selfdestruct,合约账户上剩余的以太币会发送给指定的目标,然后其存储和代码从状态树中移除。

135.solidity是一门面向合约的、为实现智能合约而创建的高级编程语言。

solidity是静态类型语言,支持继承,库和复杂的用户定义类型等特征。

除了内含标准的常见编程语言类型,还包括address等以太坊独有类型,源码以.sol为扩展名。

提供了payable等关键字,在语言层面直接支持支付。

使用变量时,需要指明内存存储或永久存储。

异常机制:一旦出现异常,所有操作都会回滚。保证合约执行的原子性。

136.solidity源代码编译会产生两份文件,字节码文件和二进制接口规范(ABI)。

137.Dapp通常通过web3.js+ABI去调用智能合约中的函数。

138.安装solcjs

npm install solc

139.智能合约部署流程

区块链学习笔记_第1张图片

140. pragma solidity ^0.4.17;

^表示大于0.4.17版本,但不大过一个大版本,即>0.4.17 <0.5.0

141.solidity语法

函数可以有多返回值。

view标记函数为只读。pure标记函数不读数据也不写数据。

定义public变量会隐式生成get该变量的方法。

使用byte类型替代string,string是不限制长度的。

构造方法constructor是在0.4.22版本之后引入的。

assert()和require()之间的区别
首先,可以将 assert() 想象为一个过于自信的实现方式,即使有错误,也会执行并扣除gas。然而 require() 可以被想象为一个更有礼貌些的实现方式,会发现错误,并且原谅所犯错误(译注:不扣除 gas)。

internal修饰词表示函数智能在该合约内部调用。

event声明了一个事件,用户可以监听区块链上正在发送的事件,而不会花费太多成本,一旦他被发出,监听该事件的listener都将收到通知。

变量默认存在storage中。

import:

区块链学习笔记_第2张图片

值类型: 

区块链学习笔记_第3张图片

fixed:fixed128x19, ufixed:ufixed128x19。M最大256,N最大80。很多版本不支持浮点数。

引用类型: 

 地址类型:

地址类型的成员变量和成员函数:

 字符数组:

区块链学习笔记_第4张图片

枚举类型: 

区块链学习笔记_第5张图片

 使用的时候需要new,State locked = State.Locked; 可以转换成任意整形。

数组:

只有在storage中的变长数组才可用.push()方法。

定长的数组length不能改变,变长的数组如果在storage中可以改变,在memory中不能改变。

pop()方法可以删除末尾元素。

struct:

区块链学习笔记_第6张图片

mapping:

区块链学习笔记_第7张图片

数据位置:

简单的局部变量会放在栈中,如uint。

区块链学习笔记_第8张图片

solidity数组也是以哈希表的形式存储的,如果是变长数组,会在定义的位置存放数组的length。

未初始化的数组指向0地址。

区块链学习笔记_第9张图片

 变量someVariable存储在0位置,局部变量x没有指向,数组x的长度也存储在0位置。

所以在调用函数f()时,变量someVariable会累加。

状态变量不能是引用类型。

陷阱合约:

区块链学习笔记_第10张图片

函数声明和类型:

函数的可见性:

函数状态可变性:

区块链学习笔记_第11张图片

区块链学习笔记_第12张图片 

区块链学习笔记_第13张图片 

函数修饰器:

区块链学习笔记_第14张图片 

回退函数:

 事件:

异常处理:

 

142.web3模块

区块链学习笔记_第15张图片 异步回调:

eth.getBlock("14",function (error,result){if(!error){console.log(JSON.stringify(result));}else {console.log(error);}})

 回调事件:

 

 

 

你可能感兴趣的:(区块链,学习)