译者注:这是距今为止行业内最全面的智能合约开发指南,强烈推荐。

软件开发的历史已有数十年之久。我们受益于半个世纪以来积累的最佳实践,设计模式和智慧。
相反,智能合约开发才刚刚开始。2015推出的以太坊和 Solidity 仅有几年的时间。
加密空间是一个不断发展的未知领域。**没有确定的工具堆栈**来构建去中心化应用。对于智能合约,没有诸如[设计模式](https://en.wikipedia.org/wiki/Design_Patterns)或[代码整洁之道](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882)之类的开发人员手册。有关工具和最佳实践的信息遍布各处。
你正在阅读**我这份希望它已经存在的指南**。总结了我从以太坊生态系统中编写智能合约,构建去中心化应用程序和开源项目中学到的经验教训。
> 这本手册是线上的文件。如果你有任何反馈或建议,请随时发表评论或[直接给我发送电子邮件](mailto:hello@yos.io)。
## 这是给谁的
本手册适用于:
* 刚开始使用智能合约的开发人员,以及
* 经验丰富的Solidity开发人员希望将他们的工作提升到一个新的水平。
但是,这并不意味着要介绍[Solidity](https://learnblockchain.cn/docs/solidity/)语言。
那就直接开始正文吧,以下我的一些建议:
## 使用开发环境
使用[Truffle](https://learnblockchain.cn/docs/truffle/)之类的开发环境(或者,[Embark](https://learnblockchain.cn/article/566), [Builder](https://buidler.dev/) [dapp.tools](http://dapp.tools/))等开发环境可以快速高效地工作。

使用开发环境可以加快经常重复执行的任务,例如:
* 编译合约
* 部署合约
* 调试合约
* 升级合约
* 运行单元测试

例如,Truffle 提供以下有用的命令:
* **compile:**将Solidity合约编译为其ABI和字节码格式。
* **console**:实例化一个交互式JS控制台,你可以在其中调用web3合约并与之交互。
* **test**:运行合约的单元测试套件。
* **migrate**:将你的合约部署到网络。
Truffle支持提供其他功能的插件。例如,[`truffle-security`](https://github.com/ConsenSys/truffle-security)提供智能合约安全性验证。 [`truffle-plugin-verify`](https://learnblockchain.cn/article/1314)在区块链浏览器上发布你的合约。你还可以创建[自定义插件](https://www.trufflesuite.com/docs/truffle/getting-started/writing-external-scripts#creating-a-custom-command-plugin)。
同样,[Builder](https://hardhat.org/plugins/) 也有越来越多的插件支持给以太坊智能合约开发人员使用。
无论使用哪种开发环境,选择一套好的工具都是必须。
## 本地开发
使用[Ganache](https://www.trufflesuite.com/ganache)(或[Ganache CLI](https://github.com/trufflesuite/ganache-cli))运行本地区块链进行开发,以“加快迭代周期”。

在主网上,以太坊交易[得付费](https://www.investopedia.com/terms/g/gas-ethereum.asp),可能需要[数分钟](https://ethgasstation.info/)才确认。使用本地链跳过所有这些等待。在本地运行合约交易免费且即时。

Ganache带有一个内置的区块浏览器,可显示你解码后的交易、合约和事件。且本地环境是[可配置](https://www.trufflesuite.com/docs/ganache/reference/ganache-settings),以满足你的测试需求。
且设置简便快捷。 [在这里下载](https://www.trufflesuite.com/ganache).
## 使用静态分析工具
静态分析或“linting”通过运行程序分析代码中的编程错误。在智能合约开发中,这对于捕获编译器可能错过的“代码风格不一致”和“易受攻击的代码”很有用。
### 1. Linters

使用[solhint](https://github.com/protofire/solhint)和[Ethlint](https://github.com/duaraghav8/Ethlint) 分析代码,Solidity的Linter与其他语言(例如JSLint)的linter相似。它们提供安全性和代码风格指南验证。
### 2.安全性分析

安全分析工具识别[智能合约漏洞](https://yos.io/2018/10/20/smart-contract-vulnerabilities-and-how-to-mitigate-them/),这些工具运行一组漏洞检测器,并打印出发现的所有问题的摘要。开发人员可以在整个实现阶段使用此信息来查找和解决漏洞。
可以选择:[Mythril](https://github.com/ConsenSys/mythril)·[Slither](https://github.com/crytic/slither)·[Manticore](https://github.com/trailofbits/manticore)·[MythX](https://mythx.io/)·[Echidna](https://github.com/crytic/echidna)·[Oyente](https://github.com/melonproject/oyente)
### 额外:使用Pre-Commit Hook
通过使用[`husky`](https://github.com/typicode/husky)设置[Git Hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks),使你的开发人员体验变得无缝,Pre-Commit Hook可让你在每次提交之前运行linters。例如:
“`
// package.json
{
“scripts”: {
“lint”: “./node_modules/.bin/solhint -f table contracts/**/*.sol”,
},
“husky”: {
“hooks”: {
“pre-commit”: “npm run lint”
}
},
}
“`
上面的代码片段在每次提交之前运行一个预定义的`lint` 任务,如果代码中存在突出的样式或安全性违规,则会失败。此设置使你团队中的开发人员能够在迭代中与linter一起使用。
## 了解安全漏洞
编写没有错误的软件非常困难。防御性编程技术只能走这么远。幸运的是,你可以通过部署新代码来修复错误。传统软件开发中的补丁程序频繁且直接。

但是,智能合约是“不可变更的”。有时无法[升级](https://yos.io/2018/10/28/upgrading-solidity-smart-contracts/)已生效的合约。在这方面,智能合约比软件开发更接近于虚拟硬件开发。
更糟糕的是,合约错误会导致巨大的财务损失。 [DAO Hack](https://medium.com/swlh/the-story-of-the-dao-its-history-and-consequences-71e6a8a551ee)损失了超过1150万以太币(在被黑客入侵时为7000万美元,现在超过了20亿美元),第二名[Parity Hack](https://hackernoon.com/parity-wallet-hack-2-electric-boogaloo-e493f2365303)损失了2亿美元的用户资金,现在DeFi领域[$ 百亿](https://defipulse.com/)市场规模一旦出错,损失将非常惨重。
智能合约开发需要与Web开发完全不同的心态。 “快速行动并打破常规”在这里不适用。你需要预先投入大量资源来编写无错误的软件。作为开发人员,你必须:
1. 熟悉Solidity [安全性](https://yos.io/2019/11/10/smart-contract-development-best-practices/) [漏洞](https://yos.io/2018/10/20/smart-contract-vulnerabilities-and-how-to-mitigate-them/),和
2. 扎实理解[设计](https://consensys.github.io/smart-contract-best-practices/recommendations/)和 [模式](https://github.com/fravoll/solidity-patterns),例如:付款提取与推送方式 以及遵循 ”检查“ – “更改” – ”交互“等。
3. 使用防御性编程技术:静态分析和单元测试。
4. 审计你的代码。
以下各节将详细说明要点(3)和(4)。
> **初学者提示:**你可以使用[Ethernauts](https://ethernaut.openzeppelin.com/)以交互方式练习Solidity安全性。
## 编写单元测试
借助**全面的测试套件**,尽早发现错误和意外行为。不同的场景测试协议可帮助你识别极端情况。
Truffle使用[Mocha](https://mochajs.org/)测试框架和[Chai](https://www.chaijs.com/)进行断言。你可以使用Javascript针对合约的包装器编写单元测试,就像前端[DApp](https://learnblockchain.cn/tags/DApp)如何调用你的合约。

从Truffle v5.1.0开始,你可以中断测试以对测试流程进行[debug](https://www.trufflesuite.com/docs/truffle/getting-started/debugging-your-contracts#in-test-debugging)并启动调试器,从而允许你设置断点,检查Solidity变量等。

Truffle缺少一些对于测试智能合约必不可少的功能。安装[openzeppelin-test-helpers](https://github.com/OpenZeppelin/openzeppelin-test-helpers)可让你访问许多重要的实用工具以验证合约状态,例如**匹配合约事件**和**向前移动时间**。
译者注: 调试智能合约还有一个选择是使用 [Build EVM 及 console.log](https://learnblockchain.cn/article/1371), 它支持在Solidity源码中打印日志查看变量。
> 或者,如果你更喜欢使用其他测试运行器,[OpenZeppelin测试环境](https://github.com/OpenZeppelin/openzeppelin-test-environment)提供了与工具无关的选项。
## 衡量测试覆盖率
编写测试是不够的。你的测试套件必须可靠地捕获回归。**[测试覆盖率](https://en.wikipedia.org/wiki/Code_coverage)**衡量测试的有效性。

具有较高测试覆盖率的程序在测试期间将执行更多代码。这意味着与覆盖率较低的代码相比,它更容易发现未被检测到的错误。
你可以使用[`solidity-coverage`](https://github.com/sc-forks/solidity-coverage)收集Solidity代码覆盖率
### 配置持续集成
拥有测试套件后,请“尽可能频繁地”运行它。有几种方法可以实现此目的:
1. 像我们之前介绍的,设置Git Hook,或者
2. 设置一个CI(持续集成:Continuous integration) 管道,在每次Git推送后执行测试。
如果你要使用现成的CI,请查看[Truffle团队](https://www.trufflesuite.com/teams)或[super blocks](https://superblocks.com/).,它们为连续进行智能合约测试提供了托管环境。

托管CI会定期运行你的单元测试,以最大程度地放心。你还可以监视已部署合约的交易,状态和事件。
## 安全审计合约
安全审计可帮助你“发现”防御性编程技术(linting,单元测试,设计模式)所遗漏的未知问题。

在这个探索阶段,你需要尽最大努力破坏合约, 如:提供意外的输入,以不同的角色调用函数等。
没有什么可以取代人工安全审计,尤其是当黑客入侵的是[整个DeFi生态系统](https://medium.com/@peckshield/bzx-hack-full-disclosure-with-detailed-profit-analysis-e6b1fa9b18fc)时。
> ️在进行下一阶段之前,你的代码应该已经通过了前面部分提到的静态分析。
## 聘请外部审计师
聘请(昂贵的)安全审计员来升级以太坊中的主要协议,他们深入研究其代码以发现潜在的安全漏洞。这些审计员结合使用专有和开源静态分析工具,例如:
* [Manticore](https://github.com/trailofbits/manticore/releases/tag/0.1.6) – 一个模拟器,能够模拟针对EVM字节码的复杂的多合约和多交易攻击。
* [Ethersplay](https://github.com/crytic/ethersplay) – 一种图形化EVM反汇编程序,能够进行方法还原,动态跳转计算,源代码匹配和二进制比较。
* [Slither](https://github.com/crytic/slither) – 静态分析器,它检测常见错误,例如重入错误,构造函数,方法访问等。
* [Echidna](https://github.com/crytic/echidna) – 面向EVM字节码的下一代智能模糊器。
审计员将帮助**识别协议中任何设计和架构级别的风险**,并知道你关于常见的智能合约漏洞。

在该过程的最后,你将获得一份报告,其中总结了审计…
- 来源:https://yos.io/2019/11/10/smart-contract-development-best-practices/ 作者:Yos Riady
- 译文出自:区块链开发网翻译计划
- 译者:Tiny 熊
- 本文永久链接:learnblockchain.cn/article…
软件开发的历史已有数十年之久。我们受益于半个世纪以来积累的最佳实践,设计模式和智慧。
相反,智能合约开发才刚刚开始。2015推出的以太坊和 Solidity 仅有几年的时间。
加密空间是一个不断发展的未知领域。没有确定的工具堆栈来构建去中心化应用。对于智能合约,没有诸如设计模式或代码整洁之道之类的开发人员手册。有关工具和最佳实践的信息遍布各处。
你正在阅读我这份希望它已经存在的指南。总结了我从以太坊生态系统中编写智能合约,构建去中心化应用程序和开源项目中学到的经验教训。
这本手册是线上的文件。如果你有任何反馈或建议,请随时发表评论或直接给我发送电子邮件。
这是给谁的
本手册适用于:
- 刚开始使用智能合约的开发人员,以及
- 经验丰富的Solidity开发人员希望将他们的工作提升到一个新的水平。
但是,这并不意味着要介绍Solidity语言。
那就直接开始正文吧,以下我的一些建议:
使用开发环境
使用Truffle之类的开发环境(或者,Embark, Builder dapp.tools)等开发环境可以快速高效地工作。
使用开发环境可以加快经常重复执行的任务,例如:
- 编译合约
- 部署合约
- 调试合约
- 升级合约
- 运行单元测试
例如,Truffle 提供以下有用的命令:
- compile:将Solidity合约编译为其ABI和字节码格式。
- console:实例化一个交互式JS控制台,你可以在其中调用web3合约并与之交互。
- test:运行合约的单元测试套件。
- migrate:将你的合约部署到网络。
Truffle支持提供其他功能的插件。例如,truffle-security
提供智能合约安全性验证。 truffle-plugin-verify
在区块链浏览器上发布你的合约。你还可以创建自定义插件。
同样,Builder 也有越来越多的插件支持给以太坊智能合约开发人员使用。
无论使用哪种开发环境,选择一套好的工具都是必须。
本地开发
使用Ganache(或Ganache CLI)运行本地区块链进行开发,以“加快迭代周期”。
在主网上,以太坊交易得付费,可能需要数分钟才确认。使用本地链跳过所有这些等待。在本地运行合约交易免费且即时。
Ganache带有一个内置的区块浏览器,可显示你解码后的交易、合约和事件。且本地环境是可配置,以满足你的测试需求。
且设置简便快捷。 在这里下载.
使用静态分析工具
静态分析或“linting”通过运行程序分析代码中的编程错误。在智能合约开发中,这对于捕获编译器可能错过的“代码风格不一致”和“易受攻击的代码”很有用。
1. Linters
使用solhint和Ethlint 分析代码,Solidity的Linter与其他语言(例如JSLint)的linter相似。它们提供安全性和代码风格指南验证。
2.安全性分析
安全分析工具识别智能合约漏洞,这些工具运行一组漏洞检测器,并打印出发现的所有问题的摘要。开发人员可以在整个实现阶段使用此信息来查找和解决漏洞。
可以选择:Mythril·Slither·Manticore·MythX·Echidna·Oyente
额外:使用Pre-Commit Hook
通过使用husky
设置Git Hook,使你的开发人员体验变得无缝,Pre-Commit Hook可让你在每次提交之前运行linters。例如:
// package.json
{
"scripts": {
"lint": "./node_modules/.bin/solhint -f table contracts/**/*.sol",
},
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
},
}
上面的代码片段在每次提交之前运行一个预定义的lint
任务,如果代码中存在突出的样式或安全性违规,则会失败。此设置使你团队中的开发人员能够在迭代中与linter一起使用。
了解安全漏洞
编写没有错误的软件非常困难。防御性编程技术只能走这么远。幸运的是,你可以通过部署新代码来修复错误。传统软件开发中的补丁程序频繁且直接。
但是,智能合约是“不可变更的”。有时无法升级已生效的合约。在这方面,智能合约比软件开发更接近于虚拟硬件开发。
更糟糕的是,合约错误会导致巨大的财务损失。 DAO Hack损失了超过1150万以太币(在被黑客入侵时为7000万美元,现在超过了20亿美元),第二名Parity Hack损失了2亿美元的用户资金,现在DeFi领域$ 百亿市场规模一旦出错,损失将非常惨重。
智能合约开发需要与Web开发完全不同的心态。 “快速行动并打破常规”在这里不适用。你需要预先投入大量资源来编写无错误的软件。作为开发人员,你必须:
- 熟悉Solidity 安全性 漏洞,和
- 扎实理解设计和 模式,例如:付款提取与推送方式 以及遵循 ”检查“ – “更改” – ”交互“等。
- 使用防御性编程技术:静态分析和单元测试。
- 审计你的代码。
以下各节将详细说明要点(3)和(4)。
初学者提示:你可以使用Ethernauts以交互方式练习Solidity安全性。
编写单元测试
借助全面的测试套件,尽早发现错误和意外行为。不同的场景测试协议可帮助你识别极端情况。
Truffle使用Mocha测试框架和Chai进行断言。你可以使用Javascript针对合约的包装器编写单元测试,就像前端DApp如何调用你的合约。
从Truffle v5.1.0开始,你可以中断测试以对测试流程进行debug并启动调试器,从而允许你设置断点,检查Solidity变量等。
Truffle缺少一些对于测试智能合约必不可少的功能。安装openzeppelin-test-helpers可让你访问许多重要的实用工具以验证合约状态,例如匹配合约事件和向前移动时间。
译者注: 调试智能合约还有一个选择是使用 Build EVM 及 console.log, 它支持在Solidity源码中打印日志查看变量。
或者,如果你更喜欢使用其他测试运行器,OpenZeppelin测试环境提供了与工具无关的选项。
衡量测试覆盖率
编写测试是不够的。你的测试套件必须可靠地捕获回归。测试覆盖率衡量测试的有效性。
具有较高测试覆盖率的程序在测试期间将执行更多代码。这意味着与覆盖率较低的代码相比,它更容易发现未被检测到的错误。
你可以使用solidity-coverage
收集Solidity代码覆盖率
配置持续集成
拥有测试套件后,请“尽可能频繁地”运行它。有几种方法可以实现此目的:
- 像我们之前介绍的,设置Git Hook,或者
- 设置一个CI(持续集成:Continuous integration) 管道,在每次Git推送后执行测试。
如果你要使用现成的CI,请查看Truffle团队或super blocks.,它们为连续进行智能合约测试提供了托管环境。
托管CI会定期运行你的单元测试,以最大程度地放心。你还可以监视已部署合约的交易,状态和事件。
安全审计合约
安全审计可帮助你“发现”防御性编程技术(linting,单元测试,设计模式)所遗漏的未知问题。
在这个探索阶段,你需要尽最大努力破坏合约, 如:提供意外的输入,以不同的角色调用函数等。
没有什么可以取代人工安全审计,尤其是当黑客入侵的是整个DeFi生态系统时。
️在进行下一阶段之前,你的代码应该已经通过了前面部分提到的静态分析。
聘请外部审计师
聘请(昂贵的)安全审计员来升级以太坊中的主要协议,他们深入研究其代码以发现潜在的安全漏洞。这些审计员结合使用专有和开源静态分析工具,例如:
- Manticore – 一个模拟器,能够模拟针对EVM字节码的复杂的多合约和多交易攻击。
- Ethersplay – 一种图形化EVM反汇编程序,能够进行方法还原,动态跳转计算,源代码匹配和二进制比较。
- Slither – 静态分析器,它检测常见错误,例如重入错误,构造函数,方法访问等。
- Echidna – 面向EVM字节码的下一代智能模糊器。
审计员将帮助识别协议中任何设计和架构级别的风险,并知道你关于常见的智能合约漏洞。
在该过程的最后,你将获得一份报告,其中总结了审计…
剩余50%的内容订阅专栏后可查看
- 发表于 2020-11-12 14:45
- 阅读 ( 7450 )
- 学分 ( 279 )
- 分类:以太坊
- 专栏:全面掌握Solidity智能合约开发