1 以太坊和比特幣工作機制的區別
- 出塊時間:以太坊出塊時間短,比特幣出塊時間大約是10min而以太坊的出塊時間大約是15s。
- Mining Puzzle:以太坊是Memory hard以及是ASIC Resistance,目前以太坊和比特幣都是proof of work 都是以工作量作爲證明,而以太坊往後想轉爲權益證明proof of stake,因此也預留了難度炸彈,用於順利過渡。
- 以太坊支持智能合約,是去中心化的合約,但還是比特幣是去中心化的貨幣。
- 以太坊是基於賬戶的。
2 以太坊是基於賬戶
2.1 Replay Attack
既然是基於賬戶那麼就有天然的抵禦Double Spending Attack的作用,花兩次錢就扣兩次的款,餘額是可以修改。但是在這一種情況下是可以防止一筆錢花兩次,但是對於收錢的人來說一筆錢就有可能收兩次了,因爲收錢方可以對外廣播這一筆交易,這就是Replay Attack。
2.2 Replay Attack的解決方法
可以通過nonce值記錄交易的次數,而且要有花錢人的簽名,例如一筆交易:
梁→曾(1eth)【梁給曾轉了一個以太幣】
nonce=1
signed 梁【梁給這一筆交易簽名】
當梁簽名後這一筆交易就變得不可篡改,除非曾知道梁的私鑰。
3 以太坊的用戶類型
3.1 外部賬戶
3.1.1 外部賬戶(Externally Owned Account)定義
外部賬戶也是指普通的用戶,和比特幣一樣誰持有私鑰就擁有了賬戶,當有了賬戶以後是不需要廣播讓全部結點都知道,只有在你的賬戶涉及到交易的時候纔可以機會讓所有結點知道。外部賬戶可以主動的發起交易並且調用合約賬戶。
3.1.2 主要屬性
- balance 餘額
- nonce 記錄第幾次交易(類似於計數器)
3.2 合約賬戶
3.2.1 合約賬戶的定義
合約賬戶可以通過按照只能合約的code內容來執行,合約賬戶和外部賬戶最大的區別是:
- 不通過公私鑰對來控制,通過該智能合約代碼控制
- 它不可以主動發起交易
3.2.2 主要屬性
- balance
- nonce一個合約賬戶調用另外一個合約賬戶也是用來計數的
- code
- storage
3.2.3 合約調用過程
創建合約→返回地址→調用合約(代碼內容不變但是存儲會改變)
4 以太坊的基本數據結構
假設單純用一個Hash表記錄所有的信息,就要考慮這筆交易是否已經包含在特定的區塊中、目前交易賬戶餘額、這個賬戶是否存在等問題這就是Merkle proof的問題,那麼是不是可以建一棵Merkle tree把所有交易都放到裏面?但是考慮到Merkle Tree的更新代價太大了,每一次新增一個交易都需要進行更新,用《比特幣的Merkle Tree》的圖,可以知道當在最後面插入一個數據的時候半棵樹都要更新,最後新生成一個Merkle Root。 但是比特幣的Merkle Tree卻不會有這種煩惱,因爲每一個區塊會有4000個左右的交易,而且這棵樹是生成以後就不需要改變了,他的Merkle Root就放在了區塊的塊頭,只是單純地用於鑑別數據是否被篡改。
MerkleTree除了檢測數據是否被篡改還有一個作用就是讓全結點保持數據的一致性。
假如只是單純的用Merkle Tree作爲數據結構的話卻不利於插入更新操作,此外當接收到的數據順序不是一致的話產生不一樣的Merkle Tree ,還是上面的圖,假如第一個Data Block的hash值和第三個Data Block的Hash值合在一起這樣合起來在算一次hash值和第一個Data Block的Hash值和第二個Data Block的hash值再合起來算一次Hash值,兩個Hash值必然不一樣。但比特幣的Merkle Tree一個區塊只有固定的一棵,那棵樹是什麼結構,掌握在記賬礦工的手上。
那麼把所有的Data Block進行排序形成一棵排序的Merkle tree,不就可以解決掉樹結構不一致的問題?但是對於插入和更新數據依然是代價很大。所以就要尋找一種數據結構結合Hash表和樹的性質,這就是引入字典樹Trie tree。
4. 1 Trie樹
4.1.1 字典樹的定義
Trie樹是一種基於樹的數據結構,又稱單詞查找樹、前綴樹,是一種哈希樹的變種。應用於字符串的統計與排序,經常被搜索引擎系統用於文本詞頻統計。用於存儲字符串以便支持快速模式匹配,主要應用在信息檢索中,Trie支持的主要查詢操作是模式匹配和前綴匹配。把luck luxury launch light生成一棵字典樹:
以上面這一課字典樹爲例子:
- 每個結點最多有26種不同的結點,在以太坊中地址有160bits用40個十六進制數表示,所以最多有0~F即16種不同的結點。
- 即使結點的順序不一樣,但是生成的樹的結構還是一樣的。
- 局部更新有着優良的特性。
4.1.2 字典樹的缺點
浪費內存,正如單詞fantasy浪費了大量的內存,所以有沒有一種數據結構可以減少內存的應用呢?
4.2 壓縮前綴樹
它能保證Trie中的每個內部結點至少有兩個字結點。通過把單子結點鏈壓縮進各條邊中來執行這個規則。
只要鍵分佈得越是稀疏壓縮的效果就會越好例如fantasy。還差一點,就是把Hash後的地址值結合壓縮前綴樹就完美了。
4.3 MPT(Merkle Patricia Tree)
把Hash後的地址值結合壓縮前綴樹。
- 根節點Hash值不可篡改。
- 滿足了Merkle Proof通過查詢value值就可以知道有多少錢。
- 有較高的查詢速率和插入效率。
- 查詢一個不存在的用戶的效率也很高。
圖源:《深入淺出以太坊MPT(Merkle Patricia Tree)》第四點
解析一下圖:
第一部分:四個賬戶keys記錄的是Hash後的地址(地址是公鑰的Hash)
第二部:有壓縮就會有一個shared nibbles
5 以太坊的三棵樹
5.1 狀態樹
需要狀態樹的原因每10s會產生一個區塊,當有分支的時候要進行回滾不合法分支的交易,直接修改賬戶狀態將會導致永久性丟失用戶數據不能回滾。對於交易樹來說查找一個賬戶就是查找這一個賬戶的地址,狀態樹記錄所有賬戶的狀態(不包含沒有發生過交易的用戶)。另外一種情況假如沒有狀態樹,此時B是一個新的賬戶,在當前區塊找不到對應的信息只好往前面的區塊找,發現也不存在B的信息直到找完創始區塊也沒有B的信息,才知道B是一個新用戶,這樣時間複雜度很高。
5.2 交易樹
每次發佈一個交易的時候就可以形成一棵交易樹,提供Merkel Proof,向輕節點證明某個交易是打包在區塊中的。
5.3 收據樹
每個交易完成後會形成一棵收據樹,記錄每一筆交易,交易樹和收據樹是一一對應的,交易樹和收據樹查找的都是每一筆交易的序號,向輕節點證明某個交易的執行結果。
5.4 交易的條件查詢
5.4.1 布隆過濾器bloom filter
布隆過濾器是一種空間效率很高的隨機數據結構,判斷一個元素是否屬於這個集合中,但是該過濾器只是支持查詢操作,不支持刪除操作。
5.4.2 布隆過濾器的過濾步驟
- 初始化時,需要一個長度爲n比特的數組barr,每個比特位初始化爲0;
- 首先需要k個hash函數,每個函數可以把key散列成爲1個整數;
- 某個key加入集合時,用k個hash函數計算出k個散列值,映射到barr的某一個位置中,並把數組中對應的比特位置爲1;
- 判斷某個key是否在集合時,用k個hash函數計算出k個散列值,並查詢數組中對應的比特位,如果所有的比特位都是1,認爲在集合中。
當所有元素都處理完後得到一個摘要。
5.4.3 布隆過濾器查詢
- 取該值的Hash值,散列成1個整數n
- 對應barr的下標n對應的值,假如是1那麼該值存在於集合中,假如值爲0則該值不存在。
注意:可能產生Hash衝突映射到同一個元素,所以布隆過濾器不保證查找的元素一定正確。
6 以太坊處理分叉問題
6.1 孤兒區塊
分叉後不能成爲最長合法鏈上的區塊。孤兒區塊假如經常出現會導致交易經常要回滾,本來得到的區塊獎勵就沒有了,重挫礦工的挖礦積極性,時長有分叉也會導致礦工的算力被分散。
6.2 叔叔區塊
6.2.1 叔叔區塊的定義
孤兒區塊變成叔叔區塊,叔叔的交易不會被執行,但他可以分取一部分的挖礦獎勵,改區塊獎勵的7/8,他也會被記錄到下一個區塊中。叔叔的個數是0~2個剩。
6.2.2 總有人想當侄子
假如產生了兩個以上的分支,剩下的叔叔區塊就沒有機會再被侄子記錄了,有點結點就是寧願不記錄叔叔區塊,他本身得到的收益減少但是和叔叔作對比,叔叔區塊反而會更虧。所以在大部分都是善意結點的情況下,會讓侄子的兒子記錄叔叔區塊的信息。藍色的兩個區塊就是解決是叔叔的問題。所以侄子和叔叔的關係可能和jojo一樣,叔叔不一定是跟父親同輩,喬瑟夫也應該喊喬魯諾舅舅。
6.2.3 叔叔的兒子沒價值
有惡意的結點偏要在叔叔鏈後面挖會導致更長的鏈更多的交易被回滾,爲了杜絕這種情況,分叉鏈只有第一個結點能收到獎勵。
6.2.4 叔叔區塊的分配問題
當叔叔區塊都會有獎勵,那麼會不會有結點就專門做分叉?如下圖:
隨着越往前叔叔區塊的錢會越來越少了到了2/8後叔叔就不會再分得獎勵。