# ETH ## ETH概述 + 區塊鏈(1.0) -> 比特幣 , 區塊鏈(2.0) -> 以太坊 + 以太坊針對BTC系統做出的改良 + 出塊時間 : 約15秒 + 全新的共識機制 : ghost 協議共識機制 + mining puzzle 改為注重內存的大小稱為 memory hard mining puzzle + 限制了 ASIC 晶片的使用,稱為 ASIC resistance + 未來(目前是POW) : POW -> POS + POW (proof of work)工作量證明 + 挖擴,就是證明你為了發布區塊前做了一堆工作 + POS (proof of stake) 權益證明 + 不挖礦,以幣的持有量來決定下一個區塊 + 對智能合約(Smart contract)的支持 + Bitcoin : decentralized currency + Ethereum : decentralized contract + 把合約以程式碼呈現,接著把這些程式碼放到區塊鏈上,依靠區塊鏈的不可竄改性,保證這個程式碼的正確運行。 + 這樣做有甚麼好處? + 透過事先寫好的程式碼,保證所有人受限於程式碼上的運行,能夠每位使用者的公平性 + 不需要依靠司法手段便能維持合約的運行 + 誰也改不了這份程式碼,連作者都不行 ## ETH 帳戶 + UTXO + BTC使用的模式 + 隱私保護比較好 + 要一次轉出全部的錢,若否則剩餘的錢將會變成手續費,或者可以再生成一個地址,傳給另一個自己(有機會的話我在自己測試) + ETH : account-based ledger + 帳戶餘額由全節點儲存並維護(儲存於狀態樹 balance 域) + 比較好的防禦 double spending attack + 你要花兩次就扣兩次R + 但是會遭遇 **replay attack**(重放攻擊) + A -> B(10ETH) + 然後(惡意節點) B 又重新廣播一次該筆交易 + 以太坊解決 replay attack 的方法 + 紀錄交易次數(nonce) + 轉帳時交易次數要包含在交易內容裡 + ![](https://i.imgur.com/FJv9Rua.png) + 全節點會維護這個 nonce 的數量,每次收到從這個地址發布的交易,nonce值都會+1 + 如果交易被重放,就驗證當前的 nonce 值和廣播的交易的 nonce 值,例如原本 nonce = 20,由A發布一筆交易後 nonce 為 21 ,replay 之後會 A 的 nonce 為21,大於等於目前的 nonce 值,表示該筆交易已經執行過了。 + ETH有兩類帳戶 + externally owned account + balance + nonce(計數器) + smart contract account + 不能主動發起交易 + nonce(計數器) + 因為合約也能呼叫外部合約 + code + storage + 創建合約後會返回地址,調用合約後 storage 就會有改變 + balance + 智能合約常被用來做為金融衍伸品 ## ETH 狀態樹 + account-based ledger + address(帳戶地址) 映射 state(帳戶狀態) + address : 160 bits(20個字節)(40個16進位的數) + 為甚麼不用 Merkle tree + 以太坊紀錄的是全部帳戶的狀態,包括餘額和交易次數,若每次出塊都要維護一棵新的 Merkle tree 代價太大。 + 為甚麼不用 sorted Merkle tree + 插入新的帳戶的代價也太大,每有一個新的帳戶大半棵樹就要重構,太蠢了 + 以太坊使用的數據結構 -> **MPT** + **trie** (取自 re**trie**val) + 字典樹、前綴樹 + ![](https://i.imgur.com/sYwN3Sv.png) + 分支數目取決於 Key 值裡每個元素的取值範圍 + 單詞結束後需要標記結束標誌符 + 查找效率取決於 Key 的長度 + **以太坊的 trie** + 每個節點最多可能有 17 個分支(branching factor) (地址為 16 進位數字 0~f + 結束標誌符) + Key 值都一樣長,都是 40 位 + 比特幣和以太坊的地址是不共用的,長度不一樣, + 以太坊地址 + 公鑰取 Hash 前面不要,只要後面的 40 位 + 使用 trie 的話只要地址不一樣就不會產生碰撞 + 不論單詞的插入順序為何,得到的樹狀結構唯一 + 更新的局部性很好,要更新某個 Key 只需要遍歷那個 Key 不用遍歷整棵樹 + 但儲存方式很浪費,一個節點只有一個子節點於是產生了 Patricia tree + 以太坊的 **Patricia tree** 或稱 **Patricia trie** + 路徑壓縮的前綴樹 + ![](https://i.imgur.com/aKfga1V.png) + 樹的高度明顯縮短,訪問效率提升 + 但若新增單詞,原路徑可能要重構 + 如果單詞少,數量長,並且彼此間幾乎沒有相似,使用 Patricia tree 效率相較於 trie 高出許多 + 例如由 + misunderstanding + decentralization + disintermediation + 組成之前綴樹 + ![](https://i.imgur.com/f0Iqo46.png) + 以太坊的帳戶大小為 2^160 ,若不使用壓縮前綴將會極度稀疏。 + 以太坊的 **MPT (Merkle Patricia tree)** + 把一般的 pointer 換成 hash pointer + 所有的帳戶依靠壓縮組成 Patricia tree 然後把 pointer 換成 hash pointer,可以計算出 root hash,一樣寫在 block header 裡面 + 以太坊中有 3 棵樹,所以有 3 個 root hash + 狀態樹 + 交易樹 + 收據樹 + **root hash** + 防止竄改,保證每個帳戶狀態不被竄改 + Merkle proof,證明帳戶有多少餘額,把自己的帳戶資料作為 hash 向上一路至 root hash + 能夠證明某個節點不存在,只要將該分支當成 Merkle proof 向上搜尋 root hash 即可 + 以太坊使用的其實是 **Modified MPT** + ![](https://i.imgur.com/gn40621.png) + 右上角 4 個帳戶,為簡單起見帳戶地址較短,並且帳戶狀態只顯示餘額 + **Extension node** + 該部位出現壓縮的節點 + nibble : 16 進位數字的意思,1 個 nibble 就表示一個 16 進制數字 + **Branch node** + 分支節點 + **Leaf node** + 葉節點 + 最後(一/幾)位 + 點跟點連接即表示,該節點內儲存著下一個點的 Hash 值 + 每次發布區塊後,這些狀態樹節點的值會發生變化,這些改變並不是儲存在原區塊內的,而是在下一個區塊 + ![](https://i.imgur.com/6mXIdzC.png) + 雖然每個區塊都有狀態樹,但其實是共享的 + 例如右邊主要都是指向左邊的節點 + 只有發生改變的節點要新建分支 + 以上圖的例子來看,帳戶的合約改變了,餘額改變了,但 code 沒變 + 每一個新的區塊都要建立一棵新的 MPT,但只會創建被更改的內容,而不是全部的 MPT + 為甚麼只記錄改變的部分 + 因為以太坊的出塊時間約為 15 秒,一旦出現分岔需要回穩(roll back),歷史紀錄就可以用來回穩(roll back) + 因為以太坊有智能合約,如果不保存之前的狀態,當交易執行完後想要推算之前的狀態,基本上是不可能的 + **block header** + ParentHash + 前一個 block header 的 hash 值 + UncleHash + CoinBase + 礦工的地址 + Root + 狀態樹的 root hash + TxHash + 交易樹的 root hash + ReceiptHash + 收據樹的 root hash + Bloom + 跟收據樹有關,提供一種高效的符合條件的查詢結果 + Diffculty + 挖礦難度 + Number + GasLimit + 和汽油費相關,因為操作智能合約需要耗費手續費 + GasUsed + Time + 大致產生區塊的時間 + Extra + MixDigest + 跟挖礦過程有關,從 Nonce 經過計算得出的 hash 值 + Nonce + 挖礦猜的隨機數 + **block struct** + header + 指向 block header 的 hash pointer + uncles + 指向 uncle block 的 hash pointer + transcations + 區塊內的交易列表 + **extblock struct(external block)** + Header + Txs + Uncles ## ETH 交易樹和收據樹 + **交易樹** + MPT + Merkle tree 類似比特幣 + 只收集當前發布區塊內的交易 + 每個區塊獨立,不共享節點 + 能提供 Merkle proof + **收據樹** + MPT + 每筆交易都會產生一個收據 + 因為智能合約執行十分複雜,依靠收據樹有利於查詢結果 + 只收集當前發布區塊內的交易 + 每個區塊獨立,不共享節點 + 能提供 Merkle proof + **Bloom filter** + 將大資料計算成一個小的向量 + 把資料取 Hash 後存入向量內 + 所有元素處理完後,得到的向量便是這個集合的摘要(digest) + ![](https://i.imgur.com/6RBllrM.png) + 例如 : 我們想要知道元素 d 是否存在上圖的集合之中,但我們無法保存整個集合 + 對 d 取 Hash ,若映射至 0 的位子,則說明集合內不包含 d + 但若和 a 映射至同樣區塊 -> (1) 哈希碰撞 (2) d == a + 使用 Bloom filter 可能出現 False positive(不在裡面可能會說在裡面,在裡面也會說在裡面,但絕對不可能在裡面說不在裡面) + 如果要刪除元素 ? + 不支持刪除操作 + 每筆交易會產生一個收據,收據內就儲存一個 Bloom filter,紀錄交易類型、地址等訊息 + **查找交易?** + 先查找哪個 block header裡的 Bloom filter 裡面有我要的交易類型 + 如果有需要的 Bloom filter 的話在往下細找 + 也可能都沒有 -> False positive + 可以快速過濾掉無關的區塊 + 為何狀態樹不保存最近交易過的帳戶就好 + 查找帳戶餘額不方便 + 如果查找新帳戶還得一路查至創世塊,發現創世塊也沒有才能確定是新帳戶 + 交易樹和收據樹的創造過程 + ![](https://i.imgur.com/zmkyhxa.png) + 在 NewBlock 裡面創建交易樹和收據樹,並且取得他們的根哈希值 + 若交易列表為空,則根哈希值為空根哈希值 + 否則使用 DeriveSha() 取得交易列表的哈希值 + 然後創建交易列表 + 判斷收據列表是否為空,為空則根哈希值為空根哈希值 + 若不為空則取根哈希值 + 創建 Bloom filter(交易列表和收據列表長度是一樣的) + 先判斷 Uncle 區塊是否為空,是的話設定成空根哈希值 + 否則使用 UncleHash 取得 Hash 通過循環創建 Uncle 數組 + DeriveSha() + ![](https://i.imgur.com/fE1xhRA.png) + 創建一棵 trie + trie + ![](https://i.imgur.com/FS3wHal.png) + 一棵 MPT + 收據的結構 + ![](https://i.imgur.com/uj4gK01.png) + Bloom 就是收據的 Bloom filter + Block Header的結構 + ![](https://i.imgur.com/2feYXyF.png) + Bloom 就是整個區塊的 Bloom filter,每個收據的 Bloom filter 合併獲得 + **CreateBloom()** + ![](https://i.imgur.com/jOX6MYN.png) + 對區塊的所有收據使用 LogsBloom 來生成 Bloom filter + 合併起來,得到整個區塊的 Bloom fliter + **LogsBloom()** + 生成每個收據的 Bloom filter + 首先對 Log 地址取 hash 後加到 Bloom filter 裡面 + **bloom9()** + Bloom filter 中使用的 hash 函數 + 把輸入映射到 digest 的 3 個位子 + **BloomLookup()** + ![](https://i.imgur.com/NWRnWHS.png) + 把 Topic 轉換成 Bytes + 然後跟 Bloom filter 取 and ## ETH GHOST + **共識機制 GHOST 協議** + 以太坊將出塊時間為十幾秒,由於底層使用的是 P2P 網路,經常會有礦工同時發布區塊,因此分岔是常態 + **一個礦池若持有全網的 x% 算力,那收益也該是整個系統的 x%,但若共識機制設定不週全則有可能獲得收益超過比例** + 例如 : 若出塊時間短、且只承認最長合法鏈,則大礦池所在處最有可能成為最長合法鏈,其他分散的礦池並沒有辦法匹敵。(mining centralization) + **GHOST 協議** + **並不是以太坊發明的,以太坊只是稍微修改** + 作廢的區塊有安慰獎 + **uncle block (分岔的區塊)** + 最長合法鏈外的區塊 + 發布的區塊能夠把 uncle block 納入,uncle block 會獲得部分出塊獎勵 + 包含 uncle block 的區塊也會獲得部分獎勵 + 鼓勵區塊進行合併 + ![](https://i.imgur.com/XuBB3ct.png) + **A 區塊包含一個 uncle block 可以獲得 (1/32 * 當前出塊獎勵)ETH** + 最長合法鏈一次最多包含兩個 uncle block + **紅色的 uncle block 被 A 容納並廣播後會獲得 (7/8 * 當前出塊獎勵)ETH 稱作(uncle reward)** + **藍色的 uncle block 被 A 容納並廣播後會獲得 (6/8 * 當前出塊獎勵)ETH** + 如果礦工惡意不包含 uncle block,則下一個區塊也能夠包含進去 + 如果同時出現三個分岔的區塊,也能被包含進入區塊鏈 + ![](https://i.imgur.com/bUbFvvB.png) + 隔 7 代的 uncle block 最少能獲得 2/8 的出塊獎勵,在前一代就沒辦法包含了 + **為甚麼只能隔 7 代** + 如果隔太遠,驗證過程會變的冗長 + 鼓勵出現分岔立刻合併,這時候取得的獎勵是最多的 + **uncle block 內的交易不執行,也不檢查合法性** + 有可能 uncle block 內的交易和主鏈上的交易相互衝突 + 不檢查內部交易的合法性,但會檢查是否為正常發布的區塊 + ![](https://i.imgur.com/Q7mhxox.png) + **如果 uncle block 是一整條鏈要給錢嗎?** + 後面的區塊通通不給錢 + 給錢的話 forking attack 的風險會變得非常低 ## ETH 挖礦算法 + 對於一個 POW(proof of work) 的系統來說,挖礦就是保證安全的途徑 + **Block chain is secured by mining.** + BTC 後的虛擬貨幣,目標大抵都是 ASIC resistance + **最常見的做法就是增加對內存的需求** + memory hard mining puzzle + **LiteCoin** + **使用 scrypt 作為挖礦算法** + 對內存需求極高 + 確實為 memory,但是對輕節點也是 memory hard,違反了原則 difficult to solve but easy to verify. + 導致 LiteCoin 不敢將內存需求開很高(128k) + ASIC resistance 失敗 + **以太坊 的 memory hard mining puzzle** + 兩個數據集一大一小 + **16MB cache** + 輕節點可以用這個 16MB cache 完成驗證 + ![](https://i.imgur.com/Z4YPIhb.png) + 起頭對一個 Seed 作運算,取得的元素作 Hash 得到第二個元素繼續作 Hash,這樣一路往下就形成了一個 cache。 + 大小會定期增長 + **1GB data set DAG** + 由 16MB cache 生產出來的 + 礦工需要保存這個 1GB 的大數據集 + ![](https://i.imgur.com/RRKPtPg.png) + 大的數據會從小數據以偽隨機的方式取得某個位子,把該位子的 Hash 值做更新/迭代,算出下一個要讀取的位子,下一個位子再做更新/迭代,算出下下一個位子,這樣來回讀 256 次,得到的數值就是大數據的其中一格資料。 + 大小會定期增長(2018 : 2.5GB) + **求解 Puzzle (ethash)** + 從大數據中以偽隨機的方式讀取 128 個數 + 根據 block header , nonce 算出一個初始的 Hash 值,根據這筆 Hash 值映射到大數據的某個位子,讀取出該位子的數字和其右邊的數字,爾後該位子的數值在做些更新/迭代,取得下一個位子,也一樣讀取該位子和其右邊,共循環 64 次,最後算出一個 Hash 值,然後比對是否符合難度。 + **Sample code** + ![](https://i.imgur.com/YgDe5j4.png) + **獲得 cache** + 第一個元素是 seed 的 hash 而後的都是前一個元素的 Hash + 每隔 30000 個區塊會改變一次 seed 值,並且每隔 30000 個區塊 cache 的容量將會增大原本的1/128。 + ![](https://i.imgur.com/JdklpaL.png) + **獲得 data set DAG 元素** + 通過 cache 生成大數據中的第 i 個元素,依照偽隨機的方式讀取 cache 中的 256 位數 + **get_int_from_item** + ETH source code 中沒有 + 用當前算出的 hash 讀出下個要算的位子 + **make_tiem** + ETH source code 中沒有 + 用 cache 中某位子的數和當前的 hash 值計算出下一個 hash 值,迭代 256 次,得到一個 64 字節的 hash 值 + **獲得整個 data set DAG** + ![](https://i.imgur.com/Ty5telB.png) + **挖礦用的函數** + ![](https://i.imgur.com/EhLcKUB.png) + **data set DAG** + 每隔 30000 個區塊會增加 1/128 倍大 + 根據 header nonce 算出初始 hash + 讀取 DAG 中兩相鄰數 + 再根據當前訊息生出下一個 hash 值 + 循環 64 次返回一個 hash 值和 difficult 比較 + **驗證用的函數** + ![](https://i.imgur.com/y42d0GZ.png) + **full size 是 DAG 的 size** + 因為輕節點沒有保存 DAG,每次驗證都要從 cache 重新生成 + 其他和挖礦函數是一樣的 + **礦工挖礦循環** + ![](https://i.imgur.com/wNBzz9t.png) + nonce : 0 ~ 2^64 + 由於礦工要驗證非常多 nonce 因此把整個 DAG 都儲存下來最快,而驗證只需要驗證一個 nonce 因此不需要儲存整個結構。 + **截至目前,以太坊挖礦還是以 GPU 為主** + **ASIC resistance 較成功** + DAG cache 較大,並且會定期增長 + **規劃要更新到 PoS(proof of stake)** + 依照所持有的硬幣進行投票,不挖礦 + **Pre-mining** + 發行貨幣時預留一部份給開發者 + **Pre-sale** + 把 Pre-mining 的加密貨幣賣出,用於開發工作 + [**關於以太坊**](https://ethernodes.org/) + [**關於以太坊**](https://etherscan.io/) + **其實有 ASIC 更安全?** + 要發動攻擊的成本極高,因為必須買入 ASIC 礦機 + 如果一般電腦都能挖礦,發動攻擊成本就會降低 ## ETH 難度調整 + 每個區塊都有可能調整難度,並且相較 BTC 複雜許多 + **區塊難度 D(H)** + ![](https://i.imgur.com/eloUPfw.png) + D(H)是本區塊的難度 + **P(H)Hd為父區塊的難度,每個區塊的難度都是以父區塊的難度基礎進行調整** + 父區塊 : 當前區塊鏈的最後一個區塊 + **𝑥 × 𝜍2 用於適應調節區塊難度,維持穩定的出塊速度** + ![](https://i.imgur.com/lIMHhSv.png) + x 為調整的單位 + ![](https://i.imgur.com/0x0klLi.png) + 𝜍2(sigma)為調整的系數 + **y 和父區塊的 uncle 數有關,如果包含 uncle 則 y = 2 否則 y = 1** + 父區塊包含 uncle 時難度會大一個單位,因為包含 uncle 時發行的貨幣量太大,需要條高難度以維持穩定 + -99 表示難度降低,最多一次降低 99 難度,主要是為了應對駭客攻擊,或其他黑天鵝事件 **+ Hs 為本區塊時間戳,P(H)Hs為父區塊時間戳,相減去即為出塊時間** + 以這部分作為基礎來調整難度 + **不帶 uncle 的父區塊(y = 1)為例** + 出塊時間[1 , 8]表示難度為 1 ,太快了,應該要上調 + 出塊時間[9 , 17]表示可以接受 + 出塊時間[18, 26]表示出塊時間太長,降低難度 + ![](https://i.imgur.com/lONX8xW.png)為難度炸彈 + ![](https://i.imgur.com/SKSXlWB.png) + 每10萬個塊難度擴大一倍,後期難度增長非常快 + 由於 ETH 未來將轉移至 PoS 會使用硬分岔的方式,如果礦工不願意更改的話,可能會出現以太坊分成兩個主鏈的問題,因此設置炸彈,讓後期的難度非常高 + ![](https://i.imgur.com/Y9vDZxR.png) + Hi'稱為 (fake block number),由 block number(Hi) 減少 300 萬得到,因為低估了 PoS 協議的開發難度,因此這麼做大約延後了1年半的時間(EIP100) + 基礎部分有下界,最小值為131072 + **以太坊發展四階段** + Froniter + Homestead + Metropolis + **Byzantium** + 難度炸彈回調就是在這個階段執行的,EIP(Ethereum improvement proposal)同時下降 ETH 出塊獎勵 + ![](https://i.imgur.com/idqXYCF.png) + 難度調整算法 + ![](https://i.imgur.com/F6YxqmW.png) + 基礎數值計算 + ![](https://i.imgur.com/mpp0O5E.png) + 難度炸彈計算 + Constantinople + Serenity ## ETH 權益證明 + **權益證明(proof of stake)** + 收益來源 -> 挖礦 -> 買設備 -> 算力 -> 越多錢收益越高,權益證明就是直接拚錢 + **virtual mining** + 依靠持有貨幣的多寡進行投票,降低能耗 + 如果要發動 51% 攻擊,必須獲得總系統 51% 貨幣才有辦法達成,類似股份制公司被收購 + 早期 PoS 遇到的問題 Nothing at stake + 一般來說,挖礦只會往最長合法鏈挖 + ![](https://i.imgur.com/xePw6oB.png) + 但是權益證明卻可以兩條鏈都下注 + **工作量證明(proof of work)** + 浪費電 + 比特幣挖礦的能耗一直隨著時間增長,總耗電量相當於智利整個國家的能耗(2018),一筆交易相當於 34 個美國家庭用電量(2018) + 以太坊的能耗,相當於冰島這個國家的能耗(2018),每筆交易相當於 2.25 個美國家庭用電量(2018) + 兩者間耗電量差別的原因是出塊時間的差距 + 若是依靠設備進行挖礦,只要外界錢夠多就會影響到他的安全,小幣種遇到這種攻擊會直接完蛋(**AltCoin infanticide**) + **權益證明 + 工作量證明(proof of deposit)** + 持有幣的人把幣用在降低難度後,進行挖礦,但是使用於降低難度的貨幣可能會被鎖定,幾個區塊之內無法再使用這些貨幣降低難度。 + **以太坊使用的權益證明**[Casper FFG](https://medium.com/taipei-ethereum-meetup/intro-to-casper-ffg-and-eth-2-0-95705e9304d6) + 過度階段曾打算和 PoW 混合使用 + 引入驗證者(Validator) + 投入一定數量的以太幣才能成為Validator,並且這些以太幣會被系統鎖定 + 兩輪投票制(Two-phase commit) + Prepare-Message + 要得到 2/3 以上的驗證者同意才能通過 + Commit-Message + 要得到 2/3 以上的驗證者同意才能通過 + 每 50 個區塊會投一次票稱為(epoch),對於上一個 epoch 來說,當前的稱作 Commit-Message ,對下一個 epoch 來說,稱為 Prepare-Message + 連續兩個 epoch 得到 2/3 以上多數同意才算有效 + ![](https://i.imgur.com/cW5Oj4Q.png) + 如果 Validator 做好自己的職責的話,可以獲得相對應的獎勵,不投票,亂投票也會被處罰 + PoS目前並不成熟,但是 PoW 卻幾乎找不到 Bug,因此 PoS 未必比較好 ## ETH 智能合約 + 智能合約就是運行在區塊鏈上的一段 code , code 的邏輯定義了合約的內容 + 目前 Solidity 是最常見的撰寫智能合約的語言,接近 JavaScript + **智能合約會記錄帳戶狀態** + balance 餘額 + nonce 交易次數 + code 交易代碼 + storage 存儲,因為以太坊的結構是一棵 MPT+ + **撰寫 Solidity** + [語法整理](https://hackmd.io/@SpaceNinja/solidity) + **GAS** + GAS USED + 這個交易花了多少 GAS + GAS PRICE + 單位 GAS 的價格 + GAS LIMIT + 這個交易最多願意支付多少的 GAS + **除了帳戶能調用合約外,合約也能調用合約,但是只有外部帳戶可以發起交易** + **直接調用** + ![](https://i.imgur.com/dnCr1WU.png) + **address.call()** + ![](https://i.imgur.com/qtAlzI4.png) + 第一個變數 funcsig 為調用的函數的簽名 + 這個例子相當於A(addr).foo(“call foo by func call”) + 和直接調用的差別在錯誤處理方式不同 + 直接調用 + 如果發起交易時發生錯誤,會連同發起交易的帳戶一同回穩 + address.call() + 錯誤處理要自己寫一個 return false; + **代理調用(delegatecall())** + 與 call() 相似,只是不能使用 value() + **fallback()** + function() public payable{} + 沒有參數,沒有返回值 + 兩種情況下會被調用 + 直接向合約地址轉帳,而不加任何 data + 被調用函數不存在 + 如果轉帳金額不是 0 需要聲明 payable ,否則將拋出異常 + **智能合約的創建** + 程式碼寫完後編譯成 Bytecode + 外部帳戶發起一筆轉帳交易到 0x0 的地址 + 轉帳金額為 0 但必須支付 GAS fee + 合約的程式碼寫在 input data 裡 + **汽油費(gas fee)** + 以太坊比起 BTC 平台,給予了一個圖靈完備的模型,可以完成非常多在 BTC 上幾乎做不到的事 + 出現無窮迴圈怎麼辦? + 以太坊把這個問題交給了使用者, + ![](https://i.imgur.com/TZx3IG6.png) + AccountNonce : 交易序號,防止 replay attack + Price: 單位汽油的價格 + GasLimit : 這個交易願意支付的最大 Gas fee + Recipient : 收款人的地址 + Amount : 轉帳金額 + Payload : data 域 + 發起智能合約時,先根據 Price,GasLimit 算出這筆交易可能消耗的汽油費,從發起者的帳戶扣掉,之後再根據實際執行情況,算出實際花費,多退,少的回穩交易 + 不同的指令消耗的 Gas fee 是不一樣的 + 例如 + + - 消耗的很少 + 取 Hash 消耗的很多 + 存儲變數消耗的 Gas fee 很多 + 只是讀取公共數據則免費 + **錯誤處理** + 在執行合約的過程中,若發生錯誤,會導致整個交易回穩,退回開始執行的狀態 + 例如 + 用完了 Gas 合約會直接回穩 + 發生錯誤時消耗的 Gas 是不會退還的 + 為了預防有人惡意的攻擊 + assert + assert(bool condition) + 若條件不滿足就拋出,用於判斷內部錯誤 + require + require(bool condition) + 若條件不滿足就拋掉,用於判斷輸入或外部錯誤 + revert + 嵌套調用 + 如果調用一個合約,那個合約發生錯誤,那兩個合約都會回穩嗎? + 直接調用 : 會 + call : 不會,返回一個 false + ![](https://i.imgur.com/c1O2dZr.png) + Gas limit + 這個的區塊內能夠用於交易的 Gas 上限 + 能夠微調 : 以上一個區塊的 Gas 作為基礎,可以調整 +-1/1024 + Receipt 數據結構 + status 域會告知礦工交易執行的結果 + 收到合約的調用後,從本地的數據結構內扣除帳戶的餘額。 + 收到合約後必須全節點必須在本地端執行一次,驗證交易,區塊內的所有交易都要無償的執行一遍 + 可不可以不執行,直接繼續挖礦? + 不可能,因為本地端的 MPT 沒有更新,其他的礦工會驗證異常 + 如果合約執行中,發生錯誤的交易需不需要發佈到區塊鏈上? + 要,因為必須扣除掉 Gas fee + 智能合約能夠依靠外部得到的訊息 + ![](https://i.imgur.com/GAg9bGR.png) + 這堂課是2018的課,但 Solidity 的變化非常快,所以語法僅供參考就好 + 智能合約可以調用的訊息 + ![](https://i.imgur.com/HfqnJb9.png) + 地址類型 + ![](https://i.imgur.com/5Z68X9M.png) + **addr.transfer()** + 當前合約給 addr 轉入多少錢 + **addr.call()** + 當前的帳戶,調用 addr 的合約 + 三種發送 ETH 的方法 + ![](https://i.imgur.com/mDKN7dh.png) + address.transfer(uint256 amount) + 若失敗會導致連鎖式的交易回穩 + 給的汽油不多,和 send 一樣 (2300) + address.send(uint256 amount) returns(bool) + 若失敗只會回傳一個 false + 給的汽油不多,和 transfer 一樣 (2300) + address.call.value(uint256 amount)() + 如果用 call 的方式轉帳,會把剩下的 Gas 一併傳送過去 + 簡單例子 + ![](https://i.imgur.com/67xaJwT.png) + ![](https://i.imgur.com/kkqmpTa.png) + 有甚麼問題 ? + ![](https://i.imgur.com/IE3Tp7P.png) + 參數是拍賣合約的地址 + ![](https://i.imgur.com/UrqFz0N.png) + 黑客用合約領錢,合約轉錢進入黑客的合約帳戶後,因為黑客的合約帳戶沒有 fallback() 函數,而會導致連鎖式的回穩,如此一來會導致合約內的所有使用者都收不到退款 + 如此一來,**完全沒辦法**取出合約內的以太幣 + 簡單例子2 + 一樣的拍賣程式碼,把auctionEnd()改成另外兩個函數取代 + ![](https://i.imgur.com/lUeV3C5.png) + ![](https://i.imgur.com/F8DCJOk.png) + 這樣可以嗎? + 由於轉帳後會立刻調用 fallback() 函數 + ![](https://i.imgur.com/ZwhH8Fm.png) + bids[msg.sender] = 0 只有在上面的 if 結束後才會執行,這時 if 和黑客的 withdraw 陷入了遞迴調用,所以不會清零 + 當三種情況發生時,遞迴調用會結束 + 合約內的錢不夠了 + 汽油費不夠了 + stackoverflow + 匯款前應該先清空/扣款 + 修改方式 + 先清零在轉帳 + 轉帳時用的是 sender() 而不是 call.value(),因為汽油費太低,不足以重複發起調用 ## ETH TheDAO + **DAO(Decentralized Autonomous Organization)** + 建立在程式碼基礎上的組織,規章是寫在程式碼裡面的,通過區塊鏈的共識協議來維持這個組織的穩定 + **The DAO** + 2016 年 5 月出現的 + 類似眾籌的投資基金,資金來源是大家在區塊鏈上的眾籌取得,用以太幣換取投票權,有的投票權越多權重越大,可以決定要投資哪個項目,之後的收益也是按照投資的比例來分配 + 極度的民主 + **splitDAO** + 可以自己從 DAO 裡面拆分出來,成立 childDAO,收回所有投票權代幣換回以太幣,讓使用者自己成立基金投資,這是唯一一個把錢取出來的方法,拆分前有七天的辯論期,拆分後有二十八天的鎖定期 + ![](https://i.imgur.com/1P4vtpO.png) + 沒有先清零就匯款,被黑客使用重入攻擊,盜領了整個組織三分之一的美元(5000萬) + **需要回穩交易的補救措施** + 依靠鎖定期的 28 天回穩交易,不讓黑客領走以太幣 + Vitalik 支持回穩,因為 the DAO 裡面有太多資金,影響太劇烈 + **不需要回穩交易的補救措施** + 並無違法,因為 code is law + 尤其是不該回穩,因為區塊鏈的不可竄改性 + **該怎麼補救?** + **從發生攻擊前的區塊開始回穩 ?** + 不只黑客的交易,會讓所有的交易都回穩了 + **軟體升級,凡是跟 TheDAO 相關的帳戶,一概不允許交易(軟分岔)** + **出現 bug** + 要是跟 TheDAO 相關的帳戶交易不被認可,還需要收取 Gas fee 嗎 ? + **以太坊沒有收取 Gas fee** + 導致出現大量的惡意攻擊,因此一堆礦工又回穩了軟體升級 + 強制讓 TheDAO 裡面的資金轉到另一個智能合約裡面,在讓使用者退款(硬分岔) + **因為以太坊要在第 192 萬個區塊,執行軟體升級,不需要 TheDAO 使用者的簽名就能確認交易(其餘礦工會認為是非法交易)** + **引起了極度激烈的辯論** + 太扯了,憑什麼轉走別人的錢 + 最後用投票的方式,大部分人支持分岔,硬分岔成功了 + 新鏈上的以太幣稱為 ETH + **反對投票的人不認帳** + 投票人數太少 + 大多數人意見也不一定是對的 + 不一定公平 + 所以,舊的鏈還是有礦工在上面挖,慢慢的,交易所上市了舊鏈的以太幣(ETC : Ethereum classic) + **硬分岔帶來的困擾 : 重入攻擊** + 新鏈上的交易,放到舊鏈上同樣合法,反過來也行,後來給兩條鏈加上了 chain ID + **為甚麼不針對黑客的帳戶就好 ?** + 因為 bug 改不了,凍結黑客的帳戶也修不了 bug,因此要從根部處理,否則任何人都能模仿黑客的手段攻擊 ## ETH 反思 + **Is smart contract really contract.** + 不智能阿,又沒有人工智慧 + Smart contract is anything but smart. + **Irrevocability is a double edged sword.** + 不可竄改性導致 bug 無法修改 + 帳戶凍結 : 軟分岔 + 一旦發生問題也不能修改 + 如果帳戶外洩? + 應該立刻把錢轉到另一個帳戶 + 一旦上鏈的合約,無法阻止其被調用 + The DAO剩下的錢怎麼處理 + 用黑客的技術把錢轉走 + **Nothing is Irrevocable** + 就連區塊鏈都是可以更改的,人是活的,程式碼是死的,不要迷信於區塊鏈的不可竄改性 + **Is solidity the right programming language?** + **Solidity轉帳就是隱性的調用別人的 fallback 函數 + 並非圖靈完備,但是能夠達成我們要的效果的語言最好 + 太難找了 + 目前大多是透過模板在撰寫合約 + **開源的 Code 保證安全?** + 智能合約的代碼公開,但還是有出現漏洞的問題 + **Many eyeball fallacy** + 雖然大家都能看到程式碼,但真的會去看的人很少 + **What does decentralization mean?** + 分岔就正是去中心化的表現,礦工可以集結決定方向 + **decentralized =/= distributed + 分布式不等於去中心化 + 智能合約不該被用於計算,而是完成邏輯操作 ## ETH 美鏈 + **美鏈(Beauty Chain)一個部署在以太坊上的智能合約,有自己的代幣 BEC** + batchtransfer函數 + 向多個接收者發送代幣,然後把代幣從調用者身上扣除 + ![](https://i.imgur.com/qXMiSz0.png) + **uint256 amount = uint256(cnt) * _value;** + 溢位問題 + ![](https://i.imgur.com/hNl0xK3.png) + **預防攻擊** + 使用已經撰寫好的函數庫 + SafeMath + ![](https://i.imgur.com/tZfkTm0.png) + 這樣就可以預防乘法出錯 + **ICO(Initial coin offering)** + 沒有自己的區塊鏈,代幣的發行、轉帳都是通過調用智能合約中的函數完成 + 可以自己定義發行規則,帳戶餘額也是保存在智能合約裡面 + ERC(Etherenum Request for Comments) 20 是以太坊上發行代幣的一個標準,規範所有發行代幣的合約應該實現的功能和遵循的街口 + 對應著狀態樹中的一點
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up