Cointime

扫码下载App
iOS & Android

编写智能合约时如何确保协议的安全性?

个人专家

作者:Brock Elmore. 编译:Cointime.com QDD

简述:

在编写require语句时,不要只为特定的函数编写require语句;要为你的协议编写require语句。函数需求-影响-交互+协议不变式(FREI-PI)模式可以通过强制开发人员专注于协议级别的不变式以及函数级别的安全性,从而使你的合约更加安全。

动机:

2023年3月,Euler Finance被黑客攻击,损失2亿美元。Euler Finance是一个借贷市场,用户可以提供抵押品并进行借贷。虽然它具有一些独特的功能,但从本质上讲,它与Compound Finance和Aave等借贷市场相似。

你可以在此处阅读有关此次黑客攻击的事后总结。简单来说,问题在于特定函数中缺少健康检查,这使得用户能够破坏借贷市场的基本不变式。

基本不变式

大多数DeFi协议都有一个不变式,即程序状态的某个属性始终为真。它们可能有多个不变式,但通常围绕一个核心思想构建。以下是一些例子:

  • 借贷市场:用户不能采取任何使任何账户处于不安全或更不安全抵押品位置的操作(“更不安全”意味着它已经低于最低安全阈值,因此不能进一步减少)
  • AMM:x * y == k,x + y == k等
  • 流动性挖矿质押:用户只能取回其存入的质押代币数量

Euler的问题不一定在于他们添加了功能、没有编写测试或没有遵循常规的最佳实践。他们审计了升级版本并进行了测试,但问题被忽略了。核心问题在于他们忘记了借贷市场的核心不变式(审计员也是如此!)。

注:我并不是要针对Euler,他们是一支有才华的团队,但这只是最近的一个鼓舞人心的例子。

问题的核心

你可能会想:“嗯,当然。这就是为什么他们被黑客攻击,他们忘记了require语句。”是的,也有一些不同。

然而,为什么他们在那里忘记了require语句呢?

Checks-Effects-Interactions模式的问题

推荐Solidity开发人员使用的一种常见模式是Checks-Effects-Interactions模式。它对于消除与递归相关的错误非常有用,并且通常会增加执行输入验证的开发人员数量。但是,它隐藏了问题的本质。

它教导开发人员:“首先编写require语句,然后进行效果操作,然后可能进行交互,就可以安全了”。问题在于,通常情况下,这变成了检查和效果的混合 - 还好吧?交互仍然是最后一个,因此递归不是问题。但是,这迫使用户专注于特定的函数和单个状态转换,换取了更少的上下文。也就是说:

仅仅使用Checks-Effects-Interactions模式会导致开发人员忘记他们的协议的核心不变式。

对于开发人员而言,这仍然是一个很好的模式,但它始终应服从于确保协议不变式的要求(认真地说,你仍然应该使用CEI!)。

正确的方式:FREI-PI模式

以前的版本中,dYdX的SoloMargin合约(源代码)是一个借贷市场和杠杆交易合约的一个精彩示例。这是我称之为“函数需求-效果-交互+协议不变式(FREI-PI)”模式的一个美好例子。

因此,我相信这是借贷市场早期阶段中唯一一个没有任何市场相关漏洞的借贷市场。Compound和Aave并没有直接受到影响,但是它们的代码分叉却受到了攻击。而bZx则遭受了多次黑客攻击

从下面的代码片段中可以看到以下抽象内容:

1. 输入要求(_verifyInputs)

2. 操作(数据转换、状态操作)

3. 状态要求(_verifyFinalState)

function operate(

Storage.State storage state,

Account.Info[] memory accounts,

Actions.ActionArgs[] memory actions

)

public

{

Events.logOperation();

scss

Copy code

 _verifyInputs(accounts, actions);

 (

     bool[] memory primaryAccounts,

     Cache.MarketCache memory cache

 ) = _runPreprocessing(

     state,

     accounts,

     actions

 );

 _runActions(

     state,

     accounts,

     actions,

     cache

 );

 _verifyFinalState(

     state,

     accounts,

     primaryAccounts,

     cache

 );

}

仍然执行常用的Checks-Effects-Interactions。值得注意的是,Checks-Effects-Interactions与额外的Checks不等同于FREI-PI-它们相似但目标根本不同。因此,开发人员应将它们视为不同的东西:FREI-PI用于协议的安全性,CEI用于函数的安全性。

该合约的结构非常有趣-用户可以连续进行多个操作(存款、借款、交易、转账、清算等)。想要存入3种不同的代币,取出第4种代币,并清算一个账户?这可以通过一次调用完成。

这就是FREI-PI的优势:用户可以在协议内部进行任何操作,只要在调用结束时核心借贷市场不变式仍然成立:用户没有采取任何使任何账户处于不安全或更不安全抵押品位置的操作。对于该合约而言,在_verifyFinalState中执行此操作,检查每个受影响账户的抵押品化程度,并确保协议比交易开始时更安全。

该函数中还包含一些额外的不变式,作为核心不变式的补充,以促进附加功能(如关闭市场),但真正保持协议安全的是核心检查。

以实体为中心的FREI-PI

FREI-PI中的一个额外细节是实体为中心的概念。以借贷市场为例,假设的核心不变式是:

用户不能采取任何使任何账户处于不安全或更不安全抵押品位置的操作

从技术上讲,这不是唯一的不变式,但对于用户实体来说是如此(它仍然是核心协议不变式,通常用户不变式是核心协议不变式)。借贷市场通常还会有两个附加实体:

1. 预言机

2. 管理员/治理

每个附加不变式都会使协议更难以保护,因此不变式越少越好。这基本上是Dan Elitzer在他那篇标题为《为什么DeFi有问题以及如何解决第一部分中所说的(提示:这篇文章实际上并没有说预言机是问题)。

预言机

对于预言机来说,以1.3亿美元的Cream Finance攻击为例。预言机实体的核心不变式是:

预言机提供准确和(相对)实时的信息

在FREI-PI中,在运行时验证预言机可能有些棘手,但可以通过一些预先考虑的方法来实现。一般而言,Chainlink是一个不错的选择,并且大多数情况下可以可靠地满足大部分不变式。在防止操纵或意外情况(例如检查上一个已知值是否比当前值大几百个百分点)的罕见情况下,减少实时性可能会更有利。再次强调一下,dYdX的SoloMargin系统在这方面做得非常出色,特别是他们的DAI预言机(如果你没有注意到,我认为它是有史以来写得最好的复杂智能合约系统)。

有关预言机评估的更多信息,并突出Euler团队的能力,他们在计算操纵Uniswap V3 TWAP预言机价格方面写了一篇很好的文章

管理员/治理

管理员是最难为不变式创建的实体。这在很大程度上是因为他们的大部分职责是更改其他不变式的保持方式。尽管如此,如果你可以避免拥有管理角色,就应该这样做。

从根本上讲,管理员实体的核心不变式可能是:

只有在效果维护所有其他不变式或故意删除或更改不变式的情况下,管理员才能采取任何操作

解释一下:管理员可以执行不破坏任何不变式的操作,除非他们正在以保护用户资金的方式进行大规模更改(例如,将资产转移至救援合约是删除不变式)。管理员还应被视为用户,因此核心借贷市场用户不变式也对他们有效(这意味着他们不能对其他用户或协议进行不当操作)。某些管理员操作目前无法通过FREI-PI在运行时验证,但是通过在其他地方设置足够强的不变式,希望大部分问题都可以得到缓解。我之所以说是目前,是因为可以想象使用zk证明系统来潜在地检查合约的整个状态(每个用户、每个预言机等)。

以管理员违反不变式为例,以2022年8月发生的破坏cETH市场的Compound治理操作为例。从根本上讲,此升级破坏了预言机不变式:预言机提供准确和(相对)实时的信息。由于缺少函数,预言机无法提供任何信息。通过运行时的FREI-PI验证,检查受影响的预言机是否能够提供实时信息,可以防止升级发生。这可以嵌入到_setPriceOracle中,检查所有资产是否接收到实时信息。FREI-PI对于管理员来说的好处是,管理员相对于价格不敏感(或至少应该是这样),因此相对于用户来说,更重的Gas使用应该不是那么重要。

复杂性是危险的

因此,尽管最重要的不变式是协议的核心不变式,但可能存在必须为核心不变式保持的实体特定不变式。但是,最简单(最小)的不变式集可能是最安全的。而关于简单性更好的光辉例子是...

为什么Uniswap从未被黑客攻击过(可能)

AMM可以有任何DeFi原始协议中最简单的基本不变式:tokenBalanceX * tokenBalanceY == k(例如,常数乘积)。Uniswap V2中的每个函数都基于这个简单的不变式:

1. 增加:增加到k

2. 销毁:从k减去

3. 交换:移动x和y,保持k不变

4. 溢出:通过修剪多余的方式重新调整tokenBalanceX * tokenBalanceY等于k

Uniswap V2的安全之道:核心不变式的简单性,所有函数都为此服务。唯一可以争议的其他实体是治理,它可以切换手续费,但不会影响核心不变式,只会影响代币余额的所有权分配。这种简单性是Uniswap从未被黑客攻击过的原因。这并不是对Uniswap智能合约出色的开发人员们的不公平待遇-找到简单性需要优秀的工程师。

Gas问题

我的Twitter提及已经充斥着对这些检查是否不必要和低效的优化恐慌和痛苦的呼声。关于这个问题有两点:

1. 你知道什么是低效的吗?不得不使用ETH转账通过以太坊区块链向劳伦斯发送消息,威胁要牵涉到联邦调查局

2. 你可能已经从存储中加载了所需的所有数据,所以只需在调用结束时使用一些带有热数据的require语句。你是希望你的协议成本稍微增加一点,还是让它在惨痛的死亡中消亡?

如果成本过高,重新考虑核心不变式并尝试简化。

对我来说意味着什么?

作为开发人员,在开发过程中及早并经常定义和阐明核心不变式。作为具体建议:第一个函数应该是_verifyAfter,它在每次调用合约后验证不变式。将其保留在合约中并部署时一同部署。此外,通过更广泛的不变式测试(在部署前进行检查),补充核心不变式(以及其他实体特定的不变式)。

临时存储提供了一些有趣的优化和改进方法,Nascent将进行尝试-我建议考虑如何将临时存储用作更好的跨调用上下文安全性工具。

在本文中,并没有花太多时间讨论FREI-PI模式中的输入验证方面,但这也非常重要。定义输入范围可能是一个具有挑战性的任务,以避免溢出等问题。考虑一下我们的工具pyrometer的进展情况,并关注它的进展:pyrometer(目前处于测试阶段,在那里给我们一个星星)。它可以提供见解并帮助你找到可能没有执行输入验证的地方。

结论

超越任何时髦的首字母缩写或模式名称,真正重要的是:

在协议的核心不变式中找到简单性。并努力确保它永远不会被破坏(或在破坏之前就能察觉到)。

评论

所有评论

推荐阅读

  • 5月14日晚间要闻速递

    1. BTC突破62000美元,24小时跌幅缩窄至1.22%

  • RWA平台Re完成700万美元新一轮融资,Electric Capital领投

    代币化再保险 RWA 平台 Re 完成 700 万美元新一轮融资,Electric Capital 领投,据悉该项目曾在 2022 年底完成 1400 万美元种子轮融资,Re 的目标是到今年年底支持 2 亿美元的保费。

  • 硅谷AI和ML开发研究实验室ChainML筹集620万美元种子轮融资

    总部位于硅谷的AI和ML开发和研究实验室ChainML最近推出了其代理基础层Theoriq,获得了620万美元的种子扩展融资。这轮融资由Hack VC领投,Foresight Ventures、Inception Capital、HTX Ventures、Figment Capital、Hypersphere Ventures和Alumni Ventures参与,以股权和代币认股权的形式进行。公司计划利用这些资金扩大其开发工作。ChainML由首席执行官Ron Bodkin领导,正在开发一种名为Theoriq的AI平台,该平台基于社会进化原则,并采用区块链实施,为不断改进、社区治理的AI系统奠定基础。

  • 北京丰台警方破获一起虚拟货币传销案

    北京丰台警方近日破获一起虚拟货币组织、领导传销犯罪案件,在这起案件中,公安部门经过调查,报案人自己就是嫌疑人。闲赋在家的谢某希望通过投资赚钱,一直寻找来钱快的“机遇”。通过朋友介绍,她加入了一个名叫“华某会”的组织,通过购买虚拟币进行投资。前期小额投资获利后,她投入了家中积蓄的200万元,但未能收到返款。被套牢后,谢某开始按传销组织要求“拉人头”,逐级提成、动态分红,使其成为该传销组织在北京的骨干分子,发展下线9级,涉及300余人。随着投资平台崩盘,谢某面对下线投资人追债,选择报警。

  • Zeta Markets完成500万美元战略融资,Electric Capital领投

    据 The Block 报道,Solana 生态 DEX 项目 Zeta Markets 完成 500 万美元战略融资,由 Electric Capital 领投,Digital Asset Capital Management (DACM)、Selini Capital 和 Airtree Ventures 参投。天使投资人包括 Solana 的 Anatoly Yakovenko、Helius 的 Mert Mumtaz、Tensor 的 Richard Wu、Pyth 的 Genia Mikhalchenko。

  • Tornado Cash 开发者 Alexey Pertsev 被判处 64 个月监禁

    荷兰法官在斯海尔托亨博斯法院裁定,Tornado Cash 开发商 Alexey Pertsev 犯有洗钱罪。法庭判处Pertsev 64 个月监禁。 2022 年 8 月,Tornado Cash 被美国政府列入黑名单后,该开发商首次在荷兰被判入狱。当时,美国财政部声称 Tornado Cash 是朝鲜黑客组织 Lazarus 的关键工具。 Lazarus 集团与 Axie Infinity 旗下 Ronin Network 遭受的价值6.25 亿美元的黑客攻击以及其他重大加密货币盗窃案有关。

  • 荷兰法院裁定Tornado Cash创始人Alexey Pertsev洗钱罪名成立

    由三名法官组成的荷兰法庭判定Tornado Cash开发者Alexey Pertsev犯有在加密货币混合平台上清洗12亿美元非法资产的罪行,预计合议庭也将在周二对居住在荷兰的31岁俄罗斯人Alexey Pertsev进行宣判,Pertsev的律师将有14天的时间对法官的判决提出上诉。专家表示,这一判决将重塑去中心化金融领域的隐私保护进程,对为用户提供金融隐私保护工具的开源软件的开发产生 "寒蝉效应"。

  • Equalizer黑客已盗取2353枚EQUAL、2500枚spLP等代币

    Fantom 生态 DEX Equalizer 今日遭到黑客攻击,到目前为止,黑客已盗取用户大约 2353 枚 EQUAL 和其他代币。该黑客的钱包地址是 222 天前建立的,并一直在接收被盗用户的资金。 攻击开始于 5 月 14 日 12 点 10 分左右,2500 个 SpookySwap 流动性代币(spLP)被耗尽,导致许多其他代币从用户那里被盗。到目前为止,被盗代币包括: 2353 枚 EQUAL; 510,579 枚 FantomStarter(FS); 2500 枚 spLP; 600 万枚 AnyInu(AI); 985,565 枚 ChillPill(CHILL); 5 万枚 WigoSwap(WIGO: 25 枚 multiDEUS(DEUS)。

  • 跨境洗黑钱集团清洗8800万港元8人被捕

    香港警方商业罪案调查科于2023年11月锁定一个跨境洗黑钱集团,调查发现集团于2023年9月至2024年3月期间,招揽内地人到香港开设傀儡银行户口,透过不同类型骗案,如电话骗案、裸聊骗案、投资骗案、求职骗案等去诈骗受害人。受害人根据骗徒指示,将骗款存入犯罪集团控制的傀儡户口,之后集团会从傀儡户口以现金方式提取骗款,并到加密货币场外交易所(OTC)购买加密货币,同时又会在海外加密货币平台上以虚假身份开设户口,并存入由骗款所购买的加密货币,再转移至多个加密货币钱包,以清洗犯罪得益。 警方又指集团利用72个本地开立的银行傀儡户口,清洗超过8800万港元犯罪得益,其中670万港元是与48宗骗案有关。至昨日,警方于全港拘捕7男1女,年龄介乎26至51岁,涉嫌串谋洗黑钱,他们分别报称救生员、摄影师、电话程式员、销售员及无业,其中6人为骨干成员,2人为傀儡户口持有人。

  • 纽约Sharp Alpha Advisors筹集2500万美元早期软件公司基金

    纽约市的风险投资公司Sharp Alpha Advisors已经为其第二个基金筹集了2500万美元,该基金的主要投资领域是体育、游戏和娱乐行业的早期软件公司。该基金计划在15家初创公司中每家投资100万至200万美元,投资对象包括面向体育博彩、幻想体育、流媒体平台和视频游戏的技术公司。该基金最近投资了总部位于伦敦的技术初创公司C15 Studio,该公司运营和分发F1和One Championship的流媒体频道。Sharp Alpha基金会创始人Danzig声称,该基金会的投资者包括一家大型美国金融公司、美国职业体育俱乐部的所有者、家族办公室、基金和与体育、游戏和娱乐产业相关的上市公司。然而,Danzig拒绝透露任何具体的个人或公司名称。该基金是Fund I的后续基金,Fund I在2021年筹集了1000万美元,主要来自高净值人士和家族办公室。Sharp Alpha在第一期基金中进行了20项投资,平均交易规模约为25万美元。