Secure Cadence 发布的突破性更新以及分析工具

Tags
Tech
Cadence
Flow
Published
May 2, 2022 05:06 AM
Language
ZH
notion image
 
本文翻译自 Flow 论坛,原文链接
你们好,开发者
我们想让每个人都知道即将到来的 6 月 Testnet & Mainnet Spork,将有一些破坏性的变化,这些变化将影响已部署的大多数智能合约。这代表着[通往 Stable Cadence 和无许可部署的道路]的关键一步(https://forum.onflow.org/t/permissionless-contract-deployment-progress/2981),我们称之为 Secure Cadence 的里程碑。
Secure Cadence 里程碑的重点是代码强化 并将支持在 Mainnet 上部署智能合约。未来的更新名为 Stable Cadence,将重点关注可用性改进。为了降低复杂性,我们将这些划分为两个里程碑,这有助于分散这些变化对团队造成的影响。
请查看下面的关键信息。

关键日期

免责声明:这些日期可能会因为 Cadence release 的安全审核和测试周期发生任何变化
  • Testnet部署: 6 月 8 日:我们将在提前一周将这些更改发布到 Testnet,以便开发人员可以测试这些更改
  • Mainnet部署: 6 月 15 日
请注意,两次 sporks 之间的时间比平常长。 在此期间,Testnet 和 Mainnet 将运行两个不同的、不兼容的 Cadence 版本。

你需要做什么

在 Testnet 和 Mainnet 上拥有智能合约的每个人都需要遵循以下步骤,以确保您的合约已准备好进行破坏性的更改。
  • Flow 核心贡献者创建了一个工具,你可以使用它来发现破坏性的变化 (文末有工具的安装与使用说明)
    • 使用包含 Secure Cadence 更改的最新 Emulator 版本在本地测试您的合约:
      • 6 月 9 日之后,在 Testnet 上测试端到端的更改时,保持本地构建就绪
      • Mainnet 部署后,网络将 对所有已部署的合约 无许可。如果您已经确定了任何影响,那么您将需要升级这些合约(您将能够自己进行升级,而无需 Flow 核心团队的任何批准或审查)。
如果您在代码审查和影响分析方面需要任何帮助,请在论坛上留下问题,或[在 Flow Discord ]寻求帮助(http://discord.gg/flow)
请查看以下破坏性更改列表

破坏性改变

引用一个可选值现在会生成一个可选类型的引用

💡 可以通过静态代码分析工具识别。
  • 更改说明:
引用可选值现在将生成可选类型的引用,而不是生成检查错误。例如:
let x: Int? = 1 let y = &x as &Int? // y 是 (&Int)? 可选类型
此外,引用字典元素现在将生成可选引用,而不是普通引用:
let dict: {String: Int} = {} let s = &dict[""] as &Int? // s 现在是可选 (&Int)? 类型 let z = &dict[""] as &Int // 这里会有类型错误
此更改将减少开发人员通过引用不存在的字典元素而意外创建对 nil 的引用的可能性。有关这一变化背后原因的更多详细信息,请参见本页:https://github.com/onflow/flow/pull/722 1
更新说明: 开发者需要添加可选的 ? 标记到字典类型的引用中,以符合新的类型规则。他们可以通过使用 ! 在引用值上标记强制转换。然而,建议开发者正确地对他们的引用进行 nil 检查,而不是强制转换他们。例如,以前看起来像这样的代码:(NFT 标准合约中的代码)
// 原有的代码 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { return &self.ownedNFTs[id] as &NonFungibleToken.NFT }
现在可以改写为:
pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! }
以满足更严格的类型检查。然而,为了受益于此更改的更高安全性,最好以这种方式编写上述代码:
pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT? { return &self.ownedNFTs[id] as &NonFungibleToken.NFT? }
然后是 nil 在使用 borrowNFT 之前检查其结果。

容器类型字段的改变现在仅限于其自身的作用域

💡  可以通过静态代码分析工具识别。
更改说明:
structresource 类型的数组和字典值,不可以在定义它们的 structresource 值之外进行修改。如果尝试这样做将会是一个类型错误。这包括通过索引赋值直接修改(例如,arr[0]=3),以及改变数组/字典的某些方法,被认为是修改的方法在文档中会有说明。因此,下面这个例子将产生一个类型错误:
pub struct Foo { pub let y: [Int] init() { self.y = [3] } } pub fun main() { let foo = Foo() foo.y.append(1) // 无效的赋值函数, 字段 `y` 不能在 `Foo` 之外被修改 }
pub(set)var 声明的字段在任何上下文中都仍然是可变的。
此更改旨在减少开发人员在仅允许读取合约或资源的内部状态时意外允许用户修改其内部状态的可能性。 有关这一变化动机的更多细节和讨论,请参见:https://github.com/onflow/flow/pull/703
更新说明: 合约作者需要审查其合约、结构和资源中具有 pub 可见性字段的位置。如果他们不希望其他合约或交易能够修改这些字段,则无需执行任何操作。如果他们希望对 setter 进行修改,则可以添加方法。例如:
pub struct Foo { pub let y: [Int] init() { self.y = [3] } pub fun appendToArray(_ x: Int) { self.y.append(x) } } pub fun main() { let foo = Foo() foo.appendToArray(1) // 可以修改 }
合约和事务作者还需要找到代码中出现新突变类型错误的地方,或者重写这些部分,以使用合约作者选择提供的任何修改器或setter方法,或者不修改其他合约的内部状态。

loadcopy 和 borrow 函数现在执行强制转换

⚠️ 无法通过静态代码分析工具识别。
变更说明: 当 storage 中的值的类型与提供的参数不匹配时,load``copyborrow不再返回nil。相反,会产生运行时错误。有关此更改的更多信息,请参见本页:https://github.com/onflow/flow/pull/718
更新说明: 开发人员需要审查这些函数的使用情况,以确保不会使用错误的类型调用它们。在开发人员希望在存储值的类型错误时返回 nil 行为的位置,他们可以使用AuthAccount 上的新 type 函数来检查存储中的值的类型([https://docs.onflow.org/cadence/language/accounts/#account-storage-api](https://docs.onflow.org/cadence/language/accounts/#account-storage-api)

参数列表中缺少逗号现在将报错

💡 可以通过静态代码分析工具识别。
变更说明: 解析器忽略了参数列表中缺少的逗号。 现在,当逗号丢失时,解析器会报告一个错误。 例如,以下程序已被接受,但本应未被接受,现在已被拒绝:
fun test(a: Int b: String) {} // ^ `a` 和 `b` 参数之间缺少逗号
更新说明: 确保参数列表在必要时包含逗号。

地址的字符串表示将会被零填充

⚠️ 无法通过静态代码分析工具识别。
变更说明: 现在,将地址转换为字符串会将用零填充。 例如:
let address: Address = 0x1 address.toString() // 结果会变成 "0x0000000000000001"
更新说明: 确保代码不依赖地址的无填充的表示

类型检查器现在推断出表达式的 通用超级类型

💡  可以通过静态代码分析工具识别。
变更说明: Cadence 类型检查现在能够通过获取每个子表达式(即:数组的每个元素、字典)的超类型来推断数组文本、字典文本和条件表达式的类型。例如:
var x = [1, 6, 35] // x 是类型 [Int] var y = [1, "hello", true] // y 是类型 [AnyStruct]
更新说明:
通过此更改,数组文字和字典文字不再使用第一个元素来推断文字的类型。因此,如果要求文本具有特定类型,则必须对整个表达式使用显式类型注释或强制转换,而不是第一个元素。
例如:将数字数组注释为“[UInt8]”: 老方法:
var x = [1 as UInt8, 6, 35]
新方式:
var x = [1, 6, 35] as [UInt8] or var x: [UInt8] = [1, 6, 35]

数字超类型上的算术、比较和位运算现在无效

💡  可以通过静态代码分析工具识别。
变更说明: 静态禁止对数值超类型执行算术、比较和按位操作,因为它们在运行时可能会成功,也可能不会成功。这样做的目的是让开发人员更清楚地了解当前在幕后发生的行为,从而帮助他们避免任何无意/不可预见的行为。
例如:
let x: Integer = 3 as Int8 let y: Integer = 4 as Int8 let z: Integer = x + y // 这会导致一个静态类型的检查错误
更新说明: 在对数字超类型执行算术/比较操作之前,开发人员必须将其显式转换为所需的类型。 更新后的代码实现了与上述示例相同的功能:
let x: Integer = 3 as Int8 let y: Integer = 4 as Int8 let z: Integer = (x as! Int8) + (y as! Int8) // 在运算之前转换成指定的类型

字符值的表示是固定的

⚠️ 无法通过静态代码分析工具识别。
变更说明:Character 类型添加运行时值。索引到字符串中(例如,str[0])现在将生成一个Character 值,而不是一个字符串,开发人员可以从正好一个字符长的字符串文本中声明Character 值,如下所示:
let a: Character = "ü" let b: Character = "\\u{FC}" let c: Character = "\\u{75}\\u{308}" let d: Character = "y" let type = a.getType() // 现在会返回 Type<Character>() 来替代之前不正确的 Type<String>()
  • 更新说明: Character值可以使用转换为字符串 toString()方法;由于某些操作产生Character 值而不是字符串而可能出现的任何类型错误,都可以通过对相关的Character 调用此方法来解决。

静态检查工具使用指引

翻译自原文
开发者你们好
Flow 核心贡献者创建了一个工具,你可以使用它来分析 Cadence 合约中最近宣布的破坏性更改,这些更改将随着下一个 spork 中的 Secure Cadence 发布而生效。 您可以在此处阅读有关 Secure Cadence 和破坏性更改的更多信息(也就是上文内容): Breaking changes coming with Secure Cadence release

安装

  • 使用包含 Secure Cadence 更改的最新 Emulator 版本测试您的合约:
    • 在 Linux 和 macOS:
      • sh -ci "$(curl -fsSL <https://storage.googleapis.com/flow-cli/install-cadence-analyzer.sh>)"
    • 在 Windows, 使用 PowerShell:
      • iex "& { $(irm '<https://storage.googleapis.com/flow-cli/install-cadence-analyzer.ps1>') }"

使用

分析账户中的合同

To analyze all contracts of an account, specify the network and address. This requires you have the Flow CLI installed and configured properly (run flow init).
要分析帐户的所有合同,请指定网络和地址。这要求你已经将Flow CLI正确安装和配置(运行flow init)。
举例:
cadence-analyzer -network mainnet -address 0x1654653399040a61

只运行一些分析程序

默认情况下,所有可用的分析器都会运行。
要列出所有可用的分析器,执行:
cadence-analyzer -help
举例:如果只想运行 reference-to-optional 和 external-mutation 分析, 执行:
cadence-analyzer -network mainnet -address 0x1654653399040a61 \\ -analyze reference-to-optional \\ -analyze external-mutation

批量分析 CSV 文件中的合约

要分析CSV文件中的所有合约,请指定该文件的路径。
举例:
cadence-analyzer -csv contracts.csv
CSV文件必须采用以下格式:
  • Header: address,name,code
  • Columns:
    • address: 合约的地址, e.g. 0x1
    • name: 合约名称, e.g. Test
    • code: 合约代码, e.g. pub contract Test {}
如果你在代码审查和影响分析方面需要任何帮助,请 在论坛发帖 , 或者到我们的 Flow Discord 寻求帮助。