自引入智能合约技术以来,Solidity 一直是智能合约开发人员首选的编码语言。
但是,如果您是 Solidity 开发人员,您已经知道它有缺点。除其他缺陷外,主要的安全问题可能源于对某些数据类型的简单错误处理,并且没有内置的访问控制。
为 Flow 区块链开发的一种新的智能合约语言Cadence从 Solidity 的疏忽中学习,并以原生方式解决了它的许多固有问题。如果您已经了解 Solidity,那么学习起来很简单!
本文介绍了 Cadence 智能合约语言,详细介绍了它如何改进 Solidity,然后在一些常见的智能合约示例中对两种语言进行了并排比较。到最后,您应该对 Cadence 感到满意并准备好开始使用 Flow!
Cadence 是为 Flow 区块链提供动力的编程语言,最初由
所有这一切都意味着 Cadence针对数字资产的创建和管理进行了高度优化。
Cadence 引入的最重要的创新是它的
Cadence 在许多方面都比 Solidity 有所改进。让我们看三个例子——小的编码错误、安全和访问控制以及合约部署。
Solidity 的一些最大问题通常源于最小的错误。例如,仅使用默认值初始化变量(尽管有时很方便)如果不更改该变量可能会导致意外结果。固定范围的数据类型可能导致潜在的下溢或溢出情况,如果该数据类型代表货币价值,这将是灾难性的。
在 Cadence 中,必须在初始化时设置变量值,从默认值中删除任何不需要的结果。此外,Cadence 中的整数会自动检查下溢或溢出情况,而您需要继承 OpenZeppelin 的安全数学库或使用高于 0.8 的版本和 Solidity。
在安全和访问控制方面,Solidity 要求您创建自定义修饰符或继承其他基于安全的智能合约,但也有许多默认公开的功能。
使用 Cadence 的基于能力的安全模型,帐户只能执行他们有权访问的功能。这意味着 Cadence 具有基本内置于语言本身的访问控制。此外,在 Cadence 中定义在资源对象上的方法不容易受到重入攻击,Solidity 开发人员在创建逻辑流时必须敏锐地意识到这一点。
当发现 Solidity 智能合约中的问题时,开发人员无法在不部署全新合约的情况下修复它们。即便如此,易受攻击的合约仍然存在。开发人员必须确保他们的用户群切换到新合同。
在 Cadence 中,智能合约可升级性是内置且透明的。当代码被声明为安全且最终的时,可以通过从智能合约的所有者那里删除密钥来使合约不可变。
总体而言,Cadence 是一种更安全、更安全的智能合约语言,出错的空间更小。
现在让我们详细看看用 Solidity 和 Cadence 编写的智能合约之间的区别。我们将介绍一个简单的 Hello World 合约,然后介绍一个更复杂的 NFT 实现。
让我们从一个历史悠久的经典开始。我们都用多种语言编写过“Hello World”,所以这是对 Cadence 的简单介绍。
让我们一步一步来。
首先,我们有合同定义。明显的区别是 Cadence 合约有一个访问控制修饰符:在本例中为 pub。此修饰符确保 Flow 网络中的每个人都可以访问合约,这是 Solidity 合约的默认行为。
但是,在 Cadence 中,我们也可以将访问控制设置为access(account)
。这限制了对部署该合约的账户的合约访问。在这里,我们已经看到了 Flow 和以太坊之间的主要区别。我们不只是将合约部署到 Flow 区块链;我们将它们部署到我们的帐户存储中。在 Flow 区块链上,每个帐户都使用存储进行初始化,其中可以存储资源和结构。这个存储有自己的权限,这让我们可以细粒度地控制谁可以执行我们的合约方法。
下一行定义了一个范围为我们合约的字符串变量。在 Cadence 中分号是可选的,并且使用let
关键字来定义变量。
Cadence 有两种类型的变量——可变的和不可变的。使用let
创建的变量是不可变的,或者称为常量;我们只能设置一次,并且在合约的生命周期内不能更改。我们使用var
关键字定义可变变量(可以更改的变量)。
在这种情况下,我们在 init 方法中设置变量值,因为 Cadence 确保每次合约部署只调用一次该方法。
与 Solidity 的constructor
等效的 Cadence 是init
方法。此方法只调用一次——在部署合约时。
在 init 方法中,我们设置了 greeting 变量的值。 Solidity 默认写入合约变量,而 Cadence 写入局部变量并要求您使用自身对象来访问合约变量。此决定可防止您在打错字时意外写入合约变量。
我们合约的第二种方法返回 greeting 变量。在 Cadence 和 Solidity 中,我们必须声明方法的访问权限是公共的,并且两种语言都要求我们定义返回类型。在这种情况下,它是一个字符串。
但是 Solidity 要求我们在这里更底层。它要求我们明确告诉它字符串的位置。它还让我们将函数标记为视图,这样我们就不会意外修改区块链的状态。
另一方面,Cadence 不需要这种低级控制,因为它是强类型和静态类型的。在程序在链上运行之前捕获潜在的错误,通过删除冗余关键字使整个方法声明更具可读性。
接下来,让我们看一下两种语言的基本 NFT 合约:
由于这两种语言对这个示例有不同的处理方式,让我们分别来看看它们:首先浏览 Solidity 示例,然后是 Cadence。
在 Solidity 中,NFT 基本上是一个 ID 列表。您必须在智能合约中跟踪这些 ID 并手动增加它们以确保唯一性。 Solidity 对 NFT 或其独特性一无所知。它只是映射到其所有者的 ID 列表,所有这些都在合同中手动管理。如果 ID 增量处理不当,这会留下错误空间,可能导致多个 NFT 具有相同的 ID。
在示例中,NFT 没有附加任何附加数据,但您可以将另一个映射 ID 添加到 URI。该合约确保每个新铸造的 NFT 都映射到所有者的地址。
当然,这是一个简单的例子。通常,您需要扩展多个接口以获得远程安全的 NFT 合约和元数据等功能,用于将众所周知的 JPG 附加到您的 NFT,但基本机制是相同的。
现在,让我们看一下 Cadence 版本以及它如何改进这个 Solidity 示例。
Cadence 示例从称为NFT
的资源类型开始。注意到NFT
前面的 @ 符号了吗?此符号是必需的,因为它确保资源类型的使用和行为将保持明确。
我们可以从资源创建实例,它可以像结构一样具有属性。与常规结构的区别在于,资源是一种特殊类型,除了它存储的数据之外,它还处理所有权。
在资源类型NFT
中,有一个 id 字段。 id
字段是一个整数UInt64
,它是赋予每个 NFT 资源的唯一 id。每个 NFT 资源的这个id
都不同,这意味着资源不能被复制或组合。接下来,使用init
函数初始化id
字段。
与Rust 的借用检查器如何确保只有一个函数可以修改变量类似,Cadence 确保其资源相同。
当我们创建一个新资源时,我们必须在存储位置周围移动它。如果我们让资源保持原样,我们的智能合约将无法正常运行,因此这迫使我们仔细考虑资源及其存储位置。这种形式的控制还可以确保资源永远不会丢失或意外删除;它们一次只能在一个位置。
当我们调用 mint 函数时,它会创建一个新的NFT
资源实例。此函数返回具有NFT
类型的资源,并从之前定义的资源中获取字段id
。 create
关键字有点像面向对象编程中的 new 运算符,创建一个新资源。 <-
或移动操作符明确表明该资源在我们调用它之后在源中不可用。
self.account
变量将指向我们用作合约部署目标的账户。正如我们之前所了解的:智能合约并未部署在 Flow 网络上的全局命名空间中,而是部署在属于您帐户的特殊链上存储中。因此,智能合约知道它被部署到了哪个账户,并且可以在其方法中使用该信息。
在本例中,我们使用帐户的保存方法。在最终的init
函数中,我们将资源移动到save
方法的第一个参数中,并告诉它帐户内的哪个路径应该存储我们的 NFT。
由于我们的 NFT 是一种资源,Flow 网络上的任何实体都无法复制它;我们不必明确地跟踪它的唯一性。
Cadence 是一种全新的智能合约编程语言,针对资产创建和管理进行了优化。这是一种现代替代方案,通过强制管理变量和资源、基础级别的安全和访问控制以及在使智能合约不可变之前升级智能合约的能力等方式来缓解 Solidity 的缺陷。 Cadence 为您打开了 Flow 生态系统的可能性,并结合了 Rust 等语言的许多功能。
因此,如果您是一名希望以更安全的语言编写智能合约的开发人员,Cadence 是一个很好的选择。要了解更多信息,请查看Cadence 文档和Flow 开发人员门户。
有一个非常棒的一天!