一个多月没更新博客了,因为我在专心开发一个智能合约进阶课程;现在,这个课程已经基本完成,我就以这篇硬广做个简单的回顾和总结吧。
我入行做程序员已经 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 分钟;课程内测也已经全部结束;从最初的设计到最终完成总共花费了六周多的时间。尽管有些小的瑕疵,但总体上讲我个人还是非常满意的。据我所知,这也是目前国内绝无仅有的高质量的智能合约开发进阶课程(重运营模式的线上课程)。
这是一个为那些和我一样在意细节、讨厌速成的开发者打造的智能合约开发进阶课程,需要时间和精力的投入,当然,还需要一些资金。不过我也相信,在这个课程中你一定会有收获!