一個多月沒更新博客了,因為我在專心開發一個智能合約進階課程;現在,這個課程已經基本完成,我就以這篇硬廣做個簡單的回顧和總結吧。
我入行做程序員已經 17 年了,但這還是我第一次寫文章來給自己做宣傳。從畢業開始,我就被不會包裝自己的問題所困擾,不知道如何在陌生人面前(比如面試的時候,哈哈)體現自己的水平可能是我這種類型的技術人員最大的弱點;我不是什么專家、大咖,更沒有什么 reputation,我就是個老程序員;和我相熟的人也許知道我的水平,但不喜社交、不愛表現、不會包裝的問題始終還是在那里。性格上的某些愚笨和遲鈍大概真的很難改變。
不過,凡事都要看兩面。我也相信認認真真做事的人不會真的沒人賞識,用心打磨的高質量內容也不會真的沒有市場,哪怕沒有什么漂亮的包裝。我不敢說自己有匠心,但我做事還是用心的。
引子 - 做這個課的動因
雖然很早就知道了比特幣,但我個人是 2016 年底才開始學習和研究區塊鏈技術的。經過了一個月左右的對 fabric 的從入門到放棄(關于這個話題,未來我應該會專門寫一篇博客來講),我把精力集中到了以太坊上。從 2017 年 3 月到 10 月的大概 7 個月左右的時間里,我用業余時間翻譯了以太坊官網的 Homestead 文檔,沒有用任何機器翻譯軟件,完全是自己讀原文來譯為中文,很笨對不對?我知道當時已經有其他人做了中文版,但我做這個事的目的還是學習、是積累,這就是我的風格。我從來不認為做技術能速成,我自己也從來不是那種臨陣磨槍就能考高分的“聰明同學”,所以我看不起那些不重細節、不重積累、不肯花時間打基礎、粗心大意的程序員們;雖然隨著年齡的增長,我不會像 20 多歲時那樣輕易表現出來,但心里的感受并沒什么變化;我也知道像我這種風格的人注定是少數,也注定是不討喜的。
到 2017 年底的時候,我基本上已經知道了以太坊是什么,它能干什么以及它正在干什么。而后就發現了目前國內文章質量最高的中文以太坊社區 Ethfans。我當時的想法還是去結合自己對軟件技術的理解和積累去做一些高質量的翻譯、提供一些高質量的內容。在今年 3 月份的時候,我很幸運的參與了 HiBlock 社區組織的 Solidity 官方文檔的中譯項目,后來也成為了管理員,對中譯版做了很多的校訂工作;同時,我開始學習以太坊黃皮書。2017 年下半年我曾經看過黃皮書,但當時真的看不懂;半年之后再來看,感覺就簡單了很多,同時也更深地理解了黃皮書的價值和它開創性的貢獻,尤其是在看了其他很多所謂“智能合約平臺”的設計(不對,應該說是借鑒,哈哈)之后。
然后我就從今年 4 月下旬開始對黃皮書的中文版(最初由猿哥和高天露中譯)的正文全文進行了獨立的校訂和增補更新(結合英文版拜占庭版本的更新,當然,也沒有用翻譯軟件),到 5 月初最終完成。至此,結合 Solidity 文檔中的相關細節,我終于覺得自己真正搞懂了以太坊、搞懂了智能合約。不過,直到現在(8月中旬)我依然沒有看到市面上有其他人在講黃皮書,無論線上還是線下(當然我自己簡單講過幾次)。我其實非常奇怪:為什么我認為的智能合約開發的必修基礎課沒有人在講呢?為什么這么有價值的、水平這么高的技術文檔沒有人在講呢?那些自己看看社區文檔就能搞定的東西反而那么多人在講呢?不過,答案其實也很簡單、很明顯,是不是?
所以,我想我該做一個真正有質量的課,給那些和我一樣關注細節、希望扎扎實實打好基礎、討厭低質量的快餐式學習的同行打造一個能真正幫助他們提高對智能合約的理解、幫助他們盡快從入門到精通的智能合約開發進階課程。
以太坊黃皮書
從課程的內容上,我認為要理解智能合約,要討論任何高級話題,都必須要首先搞懂黃皮書,因為這是以太坊的基礎,是繞不開的。如果大家看過 Solidity 文檔,應該會發現有很多技術細節在文檔里都只說了結果或者效果,但并沒說為什么是這樣,而這些明顯感覺不解渴的解釋(當然,你需要和我一樣不滿足于知其然),就是需要黃皮書幫我們解惑的。
也許有些朋友還不知道有以太坊黃皮書這么個東西,所以我們首先來看看黃皮書里到底講了什么。下面是以太坊黃皮書原文的所有章節目錄:
- Introduction
- The Blockchain Paradigm
- Conventions
- Blocks, State and Transactions
- Gas and Payment
- Transaction Execution
- Contract Creation
- Message Call
- Execution Model
- Blocktree to Blockchain
- Block Finalisation
- Implementing Contracts
- Future Directions
- Conclusion
- Acknowlegements
- Availability
- References
- Appendix A. Terminology
- Appendix B. Recursive Length Prefix
- Appendix C. Hex-Prefix Encoding
- Appendix D. Modified Merkle Patricia Tree
- Appendix E. Precompiled Contracts
- Appendix F. Signing Transactions
- Appendix G. Fee Schedule
- Appendix H. Virtual Machine Specification
- Appendix I. Genesis Block
- Appendix J. Ethash
- Appendix K. Anomalies on the Main Network
- Appendix L. List of mathematical symbolsReferences
現在清楚了吧,以太坊黃皮書是完整的以太坊協議的技術說明文檔,包含了所有的設計細節和基礎算法說明。以太坊黃皮書是世界上第一個智能合約平臺的“技術細節”說明(而不是概念性的“白皮書”),并且已經被事實證明是有效的、成功的,它在工程上的意義不言而喻。(目前絕大多數的所謂“智能合約平臺”都或多或少地“借鑒了”以太坊黃皮書所提出的設計,包括現在炒作的如日中天的某智能合約平臺)。所以,學習以太坊,學習、理解智能合約,怎么能不學黃皮書呢?
當然,以太坊黃皮書有一定難度(里邊有 300 多個數學公式/抽象表示),并且語言表述上也非?;逎?,對閱讀者而言是個很大的挑戰。我有個朋友曾說:“讀黃皮書味如嚼蠟”,很形象生動,我也很同意。所以要做進階課程,首先要面對的就是如何講解黃皮書。
這個課程的第一部分(兩課時)就是”以太坊黃皮書精簡教程“。我會把黃皮書正文中的重點內容完整地呈現給大家,沒有公式,但所有重要的細節都不會遺漏;而在第二課時中,我還會結合以太坊客戶端的實現,為大家形象地解釋以太坊的執行模型(以太坊虛擬機)。課程的目的是幫學習者先從概念上理解黃皮書中最重要的設計細節,提高他們自學黃皮書的效率和理解程度。
這第一部分的內容,也是我個人非常得意的,是我的特色,目前市面上還找不到同類的、同等質量的內容。
Openzeppelin 源代碼分析
相信已經有越來越多的開發者知道了 openzeppelin-solidity 這個項目,在以太坊生態中,這絕對是個偉大的項目。因為它提供了眾多經過社區反復審計、優化的,可復用的基礎合約模版。這在我看來也是非常非常重要的所謂“最佳實踐”,因為我從剛剛入行時就非常重視可復用的代碼和設計模式?!安灰貜驮燧喿印?!尤其是那些已經被證明很好用的、很安全的“輪子”。
在這個課程的第二部分(兩課時),我就將為大家逐一解釋這個項目中的所有合約模版的源代碼。學習這些優秀的、經過反復審計的代碼,對開發者而言就是一個很大的提高,讀懂這里邊涉及的諸多經典的設計模式,對開發者提高編碼水平、培養良好的編碼習慣也大有裨益。
雖然在我看來,這個項目里的大部分合約都不需要特別解釋,但我還是仔細的為大家整理了一個相對比較優化的學習順序,幫助大家快速了解這幾十個基礎合約。而其中關于權限控制、生命周期、支付、懸賞以及 ERC20、Crowdsale、ERC721 等合約模版都是非常有實用價值的可復用代碼。
智能合約安全開發指南
智能合約安全的問題是智能合約開發者必須面對的問題,智能合約開發也是一個典型的上手容易、精通難的技術活兒;所以,作為進階課程,這個話題也是必須要來談的。
在這個課程的第三部分(兩課時)里,我將首先為大家介紹目前所有已知的攻擊(針對 Solidity 智能合約),包括重入、算術溢出、意外之財、Delegatecall、默認的可見性、隨機錯覺、外部合約引用、短地址/參數攻擊、未檢查的返回值、競爭條件/預先交易、拒絕服務、時間戳操縱、未初始化的存儲指針、浮點和數據精度、tx.origin 判定;所有這些攻擊都會結合具體的代碼片段來講解,以幫助大家理解其中的原理和細節。而后,我將介紹智能合約安全編碼的一般原則、Solidity 智能合約開發的最佳實踐、軟件工程上的考量以及一些安全輔助工具。
智能合約開發進階
課程的第四部分(兩課時)將繼續深入介紹智能合約開發的高級話題。在第七課里,我會講解以太坊虛擬機的費用設計、指令設計,簡單地介紹 Solidity 內聯匯編,并講解合約 gas 優化的基本原則。不管用什么高級語言編寫的智能合約程序,最終都是會被編譯為 EVM 指令的,最終都會表示為 EVM 字節碼;所以從本質上講,理解 EVM 指令才是智能合約開發的終極目標,這也需要我們能真正理解 EVM 的棧(stack)、內存(memory)、存儲(storage)、calldata 和 returndata 的結構。
在這個課程的最后一課(第八課)中,我將講解三個程序實例:一個對基礎排序算法的 gas 優化實例、一個針對合約存儲和 gas 返還機制的代碼優化實例以及一個以合約實現的簡化的以太坊協議模擬器。以此來講解一些 Solidity 智能合約開發中可能會遇到的比較復雜的場景以及相應的處理實例。
課程設計和推進計劃
除了以上這些基本課程內容以外,我還精心設計了幾個需要大家真正動手的編程作業;對于初級合約開發者而言是有一定挑戰的,需要花一些時間和精力才能完成,非常有益于開發經驗的積累、提高對合約編程的理解,同時這些作業本身也有很高的實用價值。我也會單獨為大家批改每次的作業,給予相應的單獨指導。
另外,在時間安排上,以上這些內容會被分攤到四周的時間里,相對給學習者一個更充足的理解消化時間。即使如此,考慮到內容本身的難度,這個課程對于學習者來講依然是有非常大的挑戰的。不過就像我剛剛談的那樣,我不認為學技術能速成,對于這個課來講也不例外;我設計這個課,絕不是想幫大家在短時間成為智能合約“專家”(這也是不可能的),也不是簡單地教大家如何做一個 DApp 或者如何發一個 Token;而是想為那些真正想學好智能合約開發的同行“節省一些自己收集、學習相關知識點的時間”,是想為這些朋友做個領路人,幫他們理清脈絡,并提供盡可能多的信息,為未來的學習積累打下一個比較好的基礎。
這是一個精心設計、打磨的包含了非常多技術細節的課程,需要你耐心地學習、理解和積累,是可以反復咀嚼消化的;它絕不是那種只需要看一次的實操課或者簡單地對社區文檔的搬運和重復。
Solidity 真的簡單嗎?
Solidity 是一種結合了 C++、Python 和 Javascript 語言創造出來的為智能合約開發而定制的語言,雖然它在設計時沒有考慮形式化驗證(智能合約的運行結果是依賴于其本身的合約“狀態”數據和區塊鏈環境數據的,所以最初沒有考慮形式化驗證大概也是可以理解的),它的數據類型的表現力有限(比如不支持真正的元組類型、不支持多維動態數據的序列化等等),但它也確實在事實上簡化了智能合約的開發,是一種上手很容易、對初學者“很友好的”開發語言,它的技術價值是不可否認的。
不過,這種看起來“很簡單的”語言,其實并不簡單,因為有太多不那么直觀的因素會影響 Solidity 程序的運行;而大部分開發者也許并不那么理解智能合約的運行環境——以太坊虛擬機(EVM)的各種各樣的技術細節,各種各樣的大坑小坑。比如 private 函數和 public 函數在調用時到底有什么不同,僅僅是可見性么?比如數據在內存和存儲(storage)中的結構有什么區別,為什么我可以對存儲中的動態數組使用 push 和 pop,而對內存中的就不行?比如 fallback 函數是如何運作的,它真的不能接收參數也不能有返回值么?比如 transfer、send 和帶 value 的 call 有什么區別?又比如 EVM 中復雜的費用設計(尤其是存儲的使用費)和 gas 返還機制是如何影響合約的 gas 消耗(也就是運行費用)的?
如果你不關心這些細節,那這個課程就不適合你了;這個課程的目的就是要為那些關心這些細節,想真正搞懂智能合約開發的朋友講解相關的原理和語言特性,使他們理解 EVM 的運行機制、了解智能合約代碼的可能漏洞和相關最佳實踐、了解合約 gas 優化以及如何在合約中處理復雜的數據結構等等,從而成長為真正“合格的”智能合約開發者。
寫在最后
這個課程里不會講那些看看社區文檔就能掌握的基礎語法、語言特性或者學過程序設計的人都應該知道的那些基礎知識和基礎算法;課程的重點是幫助大家理解以太坊協議、理解 EVM 的機制和 Solidity 的一些高級語言特性或者不容易理解的技術細節。如果基礎知識欠缺太多,你也就很難獲得應有的收獲和提高。
在寫這篇硬廣的時候,這個課程的全部視頻已經錄制完成,總時長 12 小時左右,每課時大概 90 分鐘;課程內測也已經全部結束;從最初的設計到最終完成總共花費了六周多的時間。盡管有些小的瑕疵,但總體上講我個人還是非常滿意的。據我所知,這也是目前國內絕無僅有的高質量的智能合約開發進階課程(重運營模式的線上課程)。
這是一個為那些和我一樣在意細節、討厭速成的開發者打造的智能合約開發進階課程,需要時間和精力的投入,當然,還需要一些資金。不過我也相信,在這個課程中你一定會有收獲!