編者按:本文系 Qtum 的 Howard 葉倍巨集講師,在由掘金技術社群主辦,以太坊社群基金會、以太坊愛好者與 ConsenSys 協辦的《開發者的以太坊入門指南 | Jeth 第一期 – 北京場》 活動上的分享整理。Jeth 圍繞以太坊技術開發主題的系列線下活動。每期 Jeth 會邀請以太坊開發領域的優秀技術團隊和工程師線上下分享技術乾貨。旨在為開發者提供線下技術交流互動機會,幫助開發者成長。
分享整理傳送門
以太坊智慧合約 + DApp 從入門到上線:來自前端工程師的實戰指南 – 王仕軍 | Jeth 第一期
詳解 ERC20 代幣及眾籌 – 熊麗兵 | Jeth 第一期
Howard 是《Deep Dive Into Ethereum Virtual Machine》一書的作者,該書深度剖析了 Solidity 和以太坊的原理。目前,Howard 任 Qtum 量子鏈 DApp 平臺核心工程師,負責開發工具和資料庫。Howard 在創業界擁有10年的產品開發經驗,並且對構建去中心化產品充滿熱情。他也是本次活動的出品人。
大家好,很榮幸今天跟大家分享一下以太坊智慧合約的一些開發經驗,在開始之前,我今天先給大家先講一個高層面的介紹,從前端到後端介紹一下以太坊的技術棧;然後之後我們兩位老師會給大家去介紹一些細節。所以我的這場分享只需要大家腦海裡有個對以太坊的概念即可,具體細節後面我們兩位老師會給大家更精彩的講解。
我今天就先介紹一下智慧合約以及它存在的理由,然後帶大家看一下智慧合約長什麼樣子,最後會帶大家梳理以太坊的整個架構,從前面面對使用者的DApp到後面的儲存資料庫。
先簡單自我介紹一下,我是臺灣同胞,目前在大理遠端辦公。
為什麼要智慧合約
切入主題,為什麼要有智慧合約,挖礦非常的費資源,為什麼要花這麼多的精力這麼多的資源在挖礦上面?
有位區塊鏈先驅者提了這樣一個概念:技術讓人跟人之間去協作。我們個人自己跟自己協作,但是我可能多做一點事情,會找我的朋友找我的親人去合作,以此讓我做更大的事情,這樣我們需要一些合作,我信任我的兄弟,我信任我的同學這種型別的合作。更多的合作我們跟以太坊的愛好者我們掘金的事情我們互相的愛好及把我們捆綁在一起讓我們做更大的事情,再更大一點在一個城市,這個時候我們要有法律,我們需要各種政府部門,機關,就算我不認識你,我不認識買我產品的人,但我可以通過我們的合約去保證我們合作的可行性,更大一點就是國家跟國家、國際法院的合作等,這些跨邊界的合作是更復雜的體系。人類的文明跟技術是隨著這個合作的複雜性而增長的。
那為什麼我們要有規則呢,信任其實是非常昂貴的資源,我最信任的人就是我的親人和我的朋友,尤其是從小一起長大的朋友;但是我來到城市、國家這個級別的話,其實是很難信任一個不認識的人,所以我們要提高達成合作的可能性,就要降低信任最小的需求。我們只要通過這個概念降低互相傷害的風險,友誼的小船就不會翻。
我們要儘量的信任別人,他講這些東西是科技,我們從人跟人之間的信任上升到法律,所以我們開始講法律時就不需要提及信任。從人情到市場,我可能願意跟人合作,到市場我們開始講價格,我們有價格的協調機制,就不需要講人情了。我們點對點的對話,必須要認識你這個人我才有辦法跟你協作,多對多的撮合市場機制,這是一個持續演化的過程。
所以我們開始講這些事情的時候,會牽扯到社會擴容,社會的擴容是需要成本的,我們需要有政府,需要有法院,需要有警察機構。上圖中我們可以看到OECD政府的GDP佔比是從36%到58%不等。我們雖然沒有買單、沒有直接的去支付這些成本,但是實際上這些東西在政府開銷上佔了很大比重。那區塊鏈做的事情他是因為取代信任的機制,即以計算機替代人工成為核心的概念。所以說智慧合約他具體就是一個計算機程式,它來替代靠人工運營的這些機構。
智慧合約具體是什麼
接下來我們可看一下智慧合約具體是什麼東西。第一個例子就是亞馬遜的 LAMBDA 服務,LAMBDA一個特性是你在LAMBDA這個平臺寫程式的時候,你只是去寫你的業務邏輯,而這個業務邏輯你直接上傳到 LAMBDA 平臺上面,好像只是一個伺服器的回撥。只要有請求進來它就呼叫這個回撥,計算完成後就直接終止了,你要自己去部署一個伺服器,沒有邏輯。LAMBDA 這個平臺讓你直接把伺服器的這個業務邏輯放在平臺上面,完全不用去管後面對應哪些具體伺服器,一有請求進來,並把 LAMBDA 啟動,這個跟智慧合約的架構非常像。
我們可以看一個較為簡單的例子,這個計數器的業務邏輯很簡單,這邊有一個COUNT,把它想成資料庫裡的資料,這個合約有資料也有業務邏輯,這個業務邏輯要做的事情就是把這個數字遞增。當外部呼叫這個遞增的時候,它去資料庫裡面修改這個COUNT這個變數,這個就是你的智慧合約,從概念上來講也沒有什麼,它之所以牛逼是因為我們用去中心化的網路去同意了這個資料應該是什麼,我們具體接下來看一個更好的例子。
我們把這個合約的這些變數理解成一個資料庫,我們可能平常在寫一個加法的型別,它只是存在於型別裡面,你的假若死掉了,這個記憶體就清空了。在智慧合約裡面,雖然它是變數,但是你是寫在鏈上面,而這個資料庫恰巧是特別昂貴的資料庫。我們類比成 Java 的虛擬碼,我們會想象後面每一個合約它有一個相對應的資料儲存,它是一個物件,是一個資料庫,在這個方法裡面剛才講了遞增的方法,它只是去操作這個資料庫,在這個鍵修改它裡面的值,所以你每次去改一個變數其實是對資料庫做一個操作,而且這個操作是特別昂貴的操作,可以給一個概念,普通所有的這些指定是要費用的,普通的一個紙幣,比如說加減乘除,大概是2到5個不等,儲存的話是2萬個,大概算是5000倍的倍增。
我們看一個更完整的例子,功德香火鏈,這個例子大概介紹了智慧合約非常本質的一個東西。為什麼要寫智慧合約,我們並不是只是為了寫這個資料,他之所以牛逼是因為他裡面有金融屬性,大家可以相信你,如果在我自己的亞馬遜 LAMBDA 上搞一個功德香火鏈是沒有人相信的,我在資料庫裡面可以隨便修改,但如果我們改成在智慧合約中就變成是一個去中心化、不需要信任的一個程式。
大家來看一下這個東西,有一些需求,他初始化的時候我們要設定管理員,任何人我們都允許他捐款,最後要用這個款項的時候我們允許管理員取款,然後讓他寫出所有取款他的去處去了哪裡。
這個就是我們整個智慧合約的程式碼,就十幾行而已,這上面大概有兩點需要留意,有合約屬性,擁有者的姓名,我們會用這個屬性來儲存他的管理員,我們控制了管理員許可權才可以進行修改。下方分別是捐款和取款的函式,我們接下來把這兩個函式分開講解。
初始化設定管理員,所以說這邊我們是要把資料存起來,我們要知道誰是管理員,在建立這個合約的時候它是用一筆交易建立的,即有一個錢包去付錢然後去說這筆交易誰建立的。這裡的屬性指出當前使用者的身份,這一筆交易的操作者以及合約的操作者。我們這邊做的事情很簡單,在建立這個合約的時候我們把當前的操作者儲存在這個資料庫裡面,有了這個東西之後我們就可以驗證正在操作的人是不是管理員。
接下來我們開始做這個核心的東西,即任何人都可以轉款,之後你要做眾籌讓別人給你轉錢,這個東西就涉及到金融的屬性了。我們看到這個函式也是一樣,在操作這個把錢的使用者,我們要記下來,也就是要記下這個功德;PAYABLE 它只是一般拿來處理跟金錢相關的東西,這裡是處理存進來的錢。這裡要有個斷言,要確認這筆錢必須要大於0.001,因為我不想要太少,太少就看不上、不想要;最後這邊有一個日誌,說我們把這個輸出和這個功德記下來,然後保佑傳送這個錢的人,這個日誌就記在鏈子上面了。報錯是直接退款,他沒有滿足這一個條件這筆交易就失敗了,他捐了錢就打回原本的帳號,當然這個真實的合約你會做各種其他的需求,理念上就是你先檢查滿足了你的需求之後,你再去操作你的業務邏輯,然後最後你就可以輸出記錄這個事情。我認為比較有意思的事情,這個合約他有一個相對應的帳號,這個帳號合約有多少錢,你看裡面的業務邏輯並沒有顯性的說把這個錢給這個合約,你這個隱性只是說這一筆交易進來了,只喜歡這個邏輯,然後最後就會給這個帳號,但是你不需要程式碼直接說這個事。
接下來看看看管理員取款,我們這個函式可以讓管理員指出取錢的數量,這裡又有一個斷言,我們在斷言裡面判斷當前操作這一筆交易的人是否是這個合約的擁有者,我們一開始就要把這個擁有者記錄下來,之後的操作中我們再去驗證一下他是否是當初建立合約的人,如果是的話我就給這個使用者給他打錢,轉給他所要的錢。我們首先要做一個小測試,假如說這個帳號當前有10個以太坊幣,然後擁有者試著去取11個以太坊會發生什麼事、觸發什麼條件會報錯。假如說它試著轉錢,這邊是從合約裡面把錢轉給A,它賬戶裡面的錢不夠多就會報錯,同事狀態會直接全部回到原來的狀態。這個回滾的概念特別的重要,一般你在寫程式做一個操作的時候就有一個請求進來了,你對資料庫做一個操作,那你報錯了,之前的資料庫要回滾;以太坊會自動做這個回滾的事情,只要一失敗它就馬上回滾。
我們可以看一下一些平臺的特性,過去通常是你自己公司買這個伺服器,大家用這個服務是不用錢的;現在是使用者承擔所有的計算費用,GAS模型去計算,然後很核心的點是使用者他掌握了許可權,比如說你用支付寶想轉帳你在支付寶平臺上確認這筆帳能不能轉,那現在用客戶端在客戶端做了簽名,然後服務端說讓你轉帳,他是不會去驗證這個客戶在終端到底是誰。還有一點,雖然說以太坊或者量子,有著幾千幾萬的節點,其中以太坊是有17000多個節點,看似這17000個節點計算能力還不錯,事實上並沒有。因為每一個節點要重複每一個計算,計算每一個資料,所以當我們說儲存資料庫,如果是當成傳統資料庫來用是不可行的,因為太貴了。
去中心化平臺也是有他自己的缺點,他很慢,處理一筆交易要花20秒;其次貴,每一筆交易要花大概0.1或者是0.2美元,如果你要發一筆比較大的合約就是10美元到100塊人民幣左右了。你做應用交易的生命週期極其複雜,這個東西你必須要等他確認,等一次兩次三次,然後他可能中間會拋錯,各種不同拋錯情況,有可能是業務邏輯拋錯,也有可能是他給的GAS不夠,然後跑一半邏輯他沒有錢了,就終止了,還有一些其他的在業務上有一些沒有辦法做,沒有網路請求沒有隨機員,還有你不能更新合約程式碼,之前出了一些漏洞,有些人寫了合約,這個合約被別人刪了,然後他很多錢就卡在裡面,幾千萬美金的錢卡在裡面。所以說在做的時候就可能需要思考一下我這個東西去中心化有意義嗎,到底是哪些東西值得去中心化。
DAPP全棧走一回
那我們接下來更深入的看一下,DApp全棧走一回,我們用一個簡單的例子然後走到最後面的區塊鏈上面儲存的資料。這個合約中,我有一個變數,有一個值,然後我唯一要做的事情就是修改這個值或者是讀取這個值,這個就是我的一個簡單的智慧合約。
我們會從前端開始,我們看一下從前端再遞增RPC,這個是ABI的編碼,我們一會兒再展開來說,這個合約就是他的業務邏輯,EVM最後到區塊鏈儲存,我們一個一個展開來再說。
所以說你可以比較一下WEB 2.0到3.0他們技術站的對比,然後WEB 3.0就在吹牛說WEB3.0技術是一樣的,只是換湯不換藥,在WEB 2.0我們做了一個請求,使用者按一個鈕就產生一個請求,使用者按一個鈕就產生了一筆交易,會帶有一定的金額,這個需要整個網路去確認,而不是單一的伺服器去確認,但是在前端是由使用者批准交易之後再丟給網路讓網路去處理。然後你寫後端說我這個請求他裡面具體的資料是怎麼樣的給一些結構,那我們現在做後臺的話常常是用ABI的結構,以太坊這邊它相對應的這個資料結構就是叫做ABI編碼,傳給智慧合約的資料就是用ABI編碼,在WEB 2.0我們做服務,後來在WEB 3.0我們想寫智慧合約去做這些服務。但作業系統層面在WEB 2.0時是 Windows 這些作業系統,現在的以太坊就是虛擬機器,同時也能做一些作業系統方面的處理,比如說儲存資料轉錢,或者是呼叫其他合約,這些是用EBM來做的,這些是混合了兩個不同的東西在一起,又是虛擬機器又是作業系統。最後我們要儲存資料,就是在WEB 2.0檔案系統這些去存資料,在WEB 3.0我們有電子版本控制,你可以有各個版本。
那我們看看前端,前端要做的事情就是展現鏈上的資料,重點還是一樣,使用者在本地簽名之後再把資料提交到鏈上,這個權利是握在使用者的手上,我們可以比較一下WEB服務和純客戶端的兩個概念,大家熟悉這個應用就是幣安這種平臺做交易,實際上這些不夠形成這些許可權的控制都在平臺手上,像錢包這種東西才是比較正兒八經去中心化,你說了話不算,是使用者控制許可權。在這兩個極端去糾結如果我真的要做一個去中心化應用的話,它的使用者體驗會很差很難用;好處是中心化的服務,使用者體驗好且反應快,但是就是出了事的話那大家都一鍋掀了,現在是在兩個極端裡面去糾結怎麼做。
我們看一下前端的例子,這個REMIX IDE,他指向合約,他有兩個按鈕,一個是GET 的按紐,還有一個是SET的按鈕,我要通過呼叫的方法去改那個值。然後當我按向那個按鈕我要去設定666,這個時候他用RPC去遞交一個事物,然後在以太坊就是這個RPC的方法,他們的概念是一樣的。
所以我呼叫這個方法從我的錢包去打這個資料,然後我們之後會把這個資料去展開,它也是一個RPC,這裡面的資料傳給智慧合約的資料,我們來展開看一下。
我把剛剛那個東西呼叫到網路上面,我就可以看到這一筆交易,這個就會把交易裡面的一些資訊顯示出來,我花了多少 Gas,然後裡面傳了一些資料。
我們看 ABI 的編碼,我們可以拆開兩部分,這個 60fe47b1 他也是呼叫方法,這個是他的方法名然後拼接在一起去取這個前面四個位元組就是這個方法的選擇器,我調呼叫智慧合約的時候前面四個位元組指定我要呼叫哪些方法,後面那些就是我傳參,就是用這個編碼出來的,雖然666其實只需要2個位元組,但是他ABI編碼的設計必須要32個位元組,所以說這裡可以看到他是有一定的浪費的。剛剛傳到資料上來之後EVM的節點就會把智慧合約的程式碼加在這個裡面去執行,這個是我們剛剛設定的方法,傳值進去進行修改。
我們可以看一下EVM的位元組碼,剛剛看到這個是智慧合約,這個智慧合約最後通過編譯器會編譯到位元組碼,他基本上是從上到下一個一個執行的。我們要關注的是有兩個可以關注的,上面這邊60fe47b1這個就是我們選擇器,我先判斷一下是不是這個方法,是這個方法的話我跳到這邊來去繼續執行。所以說這個就是我們SED方法,最下面我們儲存資料了,這點是一個關鍵點,我們剛剛是要存到value這個屬性,這個屬性他可以理解為建值,他直接是對映到0的位置,我用0去儲存,最終把這個資料儲存到記憶體裡面去,所以說這是整個合約最關鍵的指令,儲存資料。
我們把剛剛說的那些東西從EVM位元組碼變成程式碼,這個是我發的時候他裡面會帶著一些資料,這個資料就是有一個指令,然後我取前面四個位元組這個就是我要選擇的方法,如果匹配了這個位元組我就跳到tag這邊,這邊我要取引數,我也是從這裡去取,我直接從四個位元組以後取32個位元組出來,這個就是我的引數,然後最後我把我讀出來的引數存到這個位置,這個就是我們剛剛合約做的事情。
我們下面分析一下sstore這個指令是在幹啥,我們剛剛做的事情就是把資料存在第一個位置,L1這個位置,這個位置可以是無限多的,我存在這個位置之後他就會更改,其實最上面的這個就是我的版本號,我的版本號他是取這兩邊的,然後每一個節點都一樣,這邊的 hash 是由下面來更改的,如果我更改了這裡面的資料,這邊的 hash 會變,然後導致最上面的這個版本號也變了,所以說直接把這個 hash 當成版本號就可以了。如果我去改動這邊的資料那通過這個路徑去改變最上面的版本,下面這邊是我儲存資料的地方,我任何地方儲存的資料都會影響到最上面的版本號,跟 top 的版本控制有點像。
這邊就是我們儲存資料的資料結構,接下來我們看一下這個資料結構最後是如何融入到鏈裡面去,這個就是我們們的區塊鏈,裡面會存著版本號,像說你去 GitHub 上面看一個專案,會有歷史更新文件,會講這個版本號修改了什麼,這個版本號修改了什麼。這個就資料結構類似於一個版本,每個版本會去記錄這一個相對應的版本號是什麼,然後從這個版本號可以取出相對版本所有的資料。
再回顧一下剛才提到的,我們從前端通過RPC,這個是以太坊節點提供的服務,通過到RPC呼叫這個節點,呼叫裡面的資料是由ABI編碼結構化,然後傳給合約,合約處理這個資料,最後這個合約是相對應位元組碼,然後由EVM解析,解析的結果通常就是存出去要麼就是給別的帳號打錢,大概就是這樣。
區塊鏈現狀&
未來
區塊鏈的現況大家體會一下,有點天下大亂的樣子,區塊鏈的新世界,這個是我們對未來的小展望,現在大概是5000萬個使用者在炒幣,可能未來十年區塊鏈會增長到10億使用者,像手機一樣普及。如果這個事成真,每個人都會有一些資料的資產,變得像手機一樣普及,這樣的話我們要討論。這就牽扯到擴容,擴容的話有幾種方案我現在比較看好側鏈和跨鏈的方案,如果我們要做產品那就考慮說這個到底怎麼樣做出好的產品給人用,所以說現在很多正在驅動的區塊鏈產品很難用被各種噴;再一個是隱私的問題,區塊鏈就是公開帳本,毫無隱私可言。
智慧合約發現了很多的問題,智慧合約在安全上或者是在可用性上面他學習成本是相當高的,因為它是不同的平臺,所用的程式語言也與其他語言不同,一切都要從頭開始學。現在我們可以看到一些新一代的智慧合約平臺可以出現了,像WEB 3.0是在瀏覽器裡面做一個接近底層的版本。所以說我們可以看到像以太坊生態圈裡面truebit在嘗試然後像rholang這類專案,它也解決了合約併發的問題,像我們公司量子我現在做一個虛擬機器,這個是模擬了CPU的架構,我們希望說通過這個架構可以支援一些比較底層的開發去做智慧合約,然後我們會比較關注像作業系統和虛擬機器的分層,現在你去分析EBM的原理,它是位元組碼,裡面會看到一些屬於作業系統的的這個指令,它其實是建在虛擬機器裡面,這個也是一個技術上的一些問題。剛剛也提到了一個問題,就是智慧合約到底能不能更新,應該怎麼更新,這也是現在行業裡面討論的問題,我們會採用一個像DGP這種方式,我們通過投票去讓使用者選擇這個智慧合約應該怎麼更新。歡迎大家跟我交流,謝謝大家。