Solidity 及 EVM 开发工具介绍

  • NIC Lin
  • 更新于 2023-01-11 10:49
  • 阅读 3587

这篇文章介绍 Ethereum 开发者的一些实用工具:Foundry 除了测试之外的功能及 VSCode 的 Solidity Visual Developer 插件

这篇文章介绍 Ethereum 开发者的一些实用工具:Foundry 除了测试之外的功能及 VSCode 的 Solidity Visual Developer 插件

0_OidMhK2MT2w2IuTK.jpg Photo by Dan Cristian Pădureț on Unsplash

Foundry

Foundry 除了提供合约开发、测试和部署,其实还有许多其他实用的功能。

安裝 Foundry

如果是 Linux 或 macOS,先安裝 foundryup,接着直接用 foundryup 指令就可以安裝。未來要升级 foundry 也只需要执行 foundryup 就好,非常简单直觉。

// Install foundryup
curl -L https://foundry.paradigm.xyz | bash
// Install or update Foundry
foundryup

详细可以参考 Foundry book 的 Installation 页面

Auto Completion

Foundry 安装完后会有 forge、cast 及 anvil 三个指令,每个指令都有许多 option,这时有 Auto Completion 会非常省事。例如产生 bash 用的 Auto Completion script:

mkdir -p $HOME/.local/share/bash-completion/completions
forge completions bash > $HOME/.local/share/bash-completion/completions/forge
cast completions bash > $HOME/.local/share/bash-completion/completions/cast
anvil completions bash > $HOME/.local/share/bash-completion/completions/anvil
exec bash

其他 Shell script 的产生方式可以参考 Foundry book 的 Shell Autocompletion 页面

anvil

其实就和 Ganache 及 hardhat node 一样:跑起一個节点。可以是全新的一个本地节点,也可以是背后连上 Forked State(例如 Forked Mainnet、Forked Goerli)的节点。如果你平常都是习惯用来跑一个短暂的全新测试节点就直接下 anvil 即可。

如果你会想在一个 Forked State 內实验或测试的话,多加上 --fork-url 和 --fork-block-number 的 option。另外可以留意 --compute-units-per-second 这个 option,它会控制每秒请求的计算量,避免取 Forked State 太频繁导致遇到像是 Alchemy Rate Limit 的问题。

更详细的节点设置可以参考 Foundry book 的 Anvil Reference 页面

cast

cast 是用来取链上资料非常好用的工具(也有送交易的工具但个人觉得不太实用)。因为有很多功能,这里我只会列出我常用及觉得实用的功能。

注:要读取链的状态记得要在 foundry.toml 档里附上 endpoint url(eth_rpc_url=$URL)或透过 --rpc-url $URL 的方式。

首先是抓取交易资讯:

  • cast tx/receipt:抓取交易receipt 资讯
  • cast run:印出一笔已被收入的交易的 execution trace 或进行 live debug(加上 --debug option),为了得到准确的交易前状态,预设会模拟执行同一区块里在该笔交易前面所有的交易,但这可能很耗时,如果只想看交易执行过程且不需要最精准的执行結果的话,可以加上 --quick option,它会跳过前面交易的模拟,直接把该笔交易当作区块的第一笔交易来执行

注:cast run --debug 的 debug 介面可能沒有那么好读,如果不需要看到执行过程中的 memory/stack/storage等细节时可以直接用 ethtx.infoTenderly ,好读很多。

cast tx $TX_HASH
cast receipt $TX_HASH
cast run $TX_HASH --quick --debug

接着是从 Etherscan 抓取合约资讯:

  • cast etherscan-source:会从 Etherscan 抓取指定地址的合约,可以加上 -d option 建立一個新的资料夹来放抓下來的合约们。记得用--etherscan-api-key 附上 Etherscan API key
    // Download WETH9 contract file to tmp folder
    cast etherscan-source -d tmp 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 --etherscan-api-key $API_KEY

    注:如果想直接在浏览器开启 VSCode 环境来浏览、编辑合约的话,可以使用 deth.net。还可以透过书签一键开启,非常方便,请参考这则 twitter

接着是 encode/decode ABI 的功能:

  • cast 4b/4bd/4be:反查 function selectorcalldata 或是 event signature。在手上只有一笔交易或一个 event 的 raw data 时,可以透过这些工具来尝试找出它要执行什么函式或 emit 了什么 event

  • cast calldata:用 function signature 及参数组出 calldata。在为多签检查或组 calldata 的时候很方便 注:因为 function selector 只有 4 bytes,如果多个 function signature 都是同一个 function selector 的话,则反查回傳所有可能 function signature

    // Decode function selector of "transfer(address,uint256)"
    cast 4b 0xa9059cbb
    // Decode calldata of a transfer
    cast 4bd 0xa9059cbb000000000000000000000000f8ed47951b8eb0997d9f038fb1fcea46b171ea2f0000000000000000000000000000000000000000000000000000000078ca2e7e
    // Decode event signature of "Transfer(address,address,uint256)"
    cast 4be 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
    // Encode calldata for a transfer
    cast calldata "transfer(address,uint256)" 0xf8ed47951B8eB0997D9F038FB1FCea46B171Ea2f 2026516094

    最后是一些转换或计算的小工具:

  • cast —-from-utf8/--to-ascii:在 hex 或字串之間转换

  • cast sig:计算 function selector

  • cast keccak:计算 keccak hash

  • cast compute-address:计算 CREATE(不是 CREATE2)的地址

    cast --from-utf8 "pls return my money"
    // 0x706c732072657475726e206d79206d6f6e6579
    cast --to-ascii 0x706c732072657475726e206d79206d6f6e6579
    // "pls return my money"
    cast sig "transfer(address,uint256)"
    // 0xa9059cbb
    cast keccak "transfer(address,uint256)"
    // 0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b
    cast compute-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --nonce 123
    // Computed Address: 0xB57130C323EC5A53F89b73c9cA6f9Fc3c11744f6

    更多 cast 功能可以参考 Foundry book 的 cast Commands 页面。你可以从中按照你的需求找到对你有帮助的常用指令。

forge inspect

forge 的 inspect 指令则是用来挖出一个合约更进阶的资讯。它不是去拉链上的资料,而是作用在本地端的档案(例如 MyContract),所以如果你需要分析(链上的)其他合约,你需要先把它下载下来。

forge inspect MyContract ...

注:在分析前 forge 会先编译合约,会花一些时间。

首先是列出合约基本资料的功能:

  • forge inspect MyContract abi/bytecode/deployedBytecode:列出 MyContract的 ABI/编译完的 bytecode/实际部署到链上后的 bytecode,方便 export ABI 或是比对部署在链上的 bytecode
  • forge inspect MyContract methods/gas:列出 MyContract的(public 的) function 列表(包含 function signature 及 selector)/ 每个 function 的预估 gas 消耗 。用 cast 4b/4bd 其实就能反查特定 function selector,这个功能比较像是能看到一个合约完整的 function 资讯
  • forge inspect MyContract storage:列出 MyContract的 storage,包含每个变数的 storage slot 和 offset(如果有多个变数被 pack 在一起的话,offset 会是每个变数在该 slot 的起始位置)。但呈现的资料比较丑一点,可以改用 slither 来分析合约 storage 或读取合约变数的值,它还可以拉链上的合约来分析,不需要先下载合约下来。

接下來是比较进阶的使用:irOptimized(或 iro),主要是你想再优化你合約的 gas 消耗时可以采用的方式。

forge inspect MyContract irOptimized

它会呈现你的合约编译成(优化过的)Yul 后的长相。Yul 就像 assembly,它介于 Solidity 和 EVM opcode 之间,它可以让你看到你写的 Solidity function 背后实际上还做了哪些事情,如此你就可以开始刪去一些不需要的检查。

这个工具是从这两则 twitter(link1, link2)发现到的,这边直接引用里面的范例和图片来搭配说明。以一个简单的将 number 变数递增的 Counter 合约为例,里面有一个 setNumber 函式用来设置 number 的值及一个 increment 函式用来把 number 加 1。右边则是执行 forge inspect Counter irOptimized 后所输出 Yul 版本的 Counter 合约:

1.jpeg

source: https://twitter.com/w1nt3r_eth/status/1579486967963693057 可以看到一个简单的 Solidity 合约编译完后变得复杂许多。接下来以 increment 函式为例:

2.jpeg source: https://twitter.com/w1nt3r_eth/status/1579486967963693057 可以发现一个number++里面其实包含了很多检查,例如 not payable 和 overflow。但其实我们知道它只会以一次加 1 的方递增所以几乎不可能会 overflow(加上 unchecked),然后如果这个函式是可以接受 ether 的话,那就可以再省掉 not payable 的检查(加上 payable):

3.jpeg source: https://twitter.com/w1nt3r_eth/status/1579486967963693057 可以发现省去了许多执行步骤。

比起原地把 Solidity 程式码替换成assembly 程式码这个比较冒险的优化方式,这是一个新的管道让你能重新完整地检视你的合約,並且可以看出修改前后的对比。但要注意还是以安全为优先,不要为了省一点的 gas 而拿掉你沒有把握的程式码或检查。

其他 forge inspect 功能可以参考 Foundry book 的 forge inspect 页面

VSCode

最后是介绍一个在 review 合约时很实用的 VSCode 插件:Solidity Visual Developer

注:以下介绍会是个人使用心得,所以会有特色或功能是沒有介绍到的。可以自己下载来试用看看,看能不能发现适合你的用途的功能。

Solidity Visual Developer - Visual Studio Marketplace 🌐 📩 🔥 ] Advanced Solidity Language Support Code Augmentation Source Exploration Visual Security Linting An extension… marketplace.visualstudio.com https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor

里面最常看到的就是它为你合约的变数套上框框并能连结到宣告变数的地方,以及函式的参数套上底色方便识别(虽然有时候颜色太多会看得有点眼花)。另外有 variable shadowing 的警告提醒,例如你的合约继承了 Ownable 合约但某个函式宣告了一个 owner 参数,这时候这个 owner 参数就会被套上显眼的红色框框来提醒你:

5.png owner 变数被 owner 参数 shadow 了

keywords 例如 block.timestamp、tx.origin、msg.data 或是 external 等等关键字都有提供 hover时显示安全提醒:

6.png block.timestamp 的安全提醒

7.png external 的安全提醒 如果你在 review 合约需要做笔记时,可以利用 @audit 及 @audit-ok 这两个 tag,它会出现像 Bookmarks 那样的图示方便你回到笔记过的程式码段落:

8.png @audit 及 @audit-ok 分別显示红色及绿色的书签提示 它还有提供一些分析整個合约的功能,让你能得到不同合约间的继承关系(inheritance)和函式之间的关系(graph),这边直接使用官方的图:

9.gif https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor

10.png https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor 还有其他工具像是 flatten:

11.png Solidity Visual Developer 这个插件对 review 或审计合约算是非常有幫助,但写合约时帮助比较少。虽然对一般人来说里面大部分的工具其实平常几乎都用不太到,不过至少知道有哪些工具可以使用之后,未来有天当你需要 review 合约的时候它们就可以派上用场。

Thanks to Cyan Ho

本文首发于:https://medium.com/taipei-ethereum-meetup/tools-for-debugging-solidity-and-evm-interaction-285f2bfb9c17

点赞 4
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
NIC Lin
NIC Lin
江湖只有他的大名,没有他的介绍。