Solana 没有 fallback 或 receive 函数
Solana 交易必须预先指定作为交易一部分将被修改或读取的账户。如果 fallback 函数访问了一个未确定的账户,那么整个交易将会失败。这将让用户承担起预先知晓 fallback 函数将访问哪些账户的责任。因此,直接禁用这类函数要简单得多。
Solana 没有 “view” 或 “pure” 函数的概念
Solidity 中的 view 函数通过两种机制来提供状态不会改变的保证:
- 在
view函数中的所有外部调用都是 staticcalls(如果发生状态改变则会回退的调用) - 如果编译器检测到会改变状态的操作码,它会抛出错误
pure 函数则更进一步,编译器甚至会检查是否存在读取状态的操作码。
这些函数限制主要发生在编译器层面,而 Anchor 并没有实现任何此类编译器检查。Anchor 并不是构建 Solana 程序的唯一框架。Seahorse 是另一个选择。也许以后会有其他框架出现,带有明确声明函数能做什么和不能做什么的函数注解,但目前我们可以依赖以下保证:如果一个账户没有包含在 Context 结构体定义中,那么该函数就不会访问那个账户。
这并不意味着该账户完全无法被访问。例如,我们可以编写一个独立的程序来读取某个账户,并以某种方式将该数据转发给目标函数。
最后,在 Solana 虚拟机或运行时中不存在 staticcall 这样的概念。
无论如何,在 Solana 中 view 函数都是不必要的
因为 Solana 程序可以读取传递给它的任何账户,所以它可以读取属于另一个程序的账户。
拥有该账户的程序不需要实现 view 函数来授权另一个程序查看该账户。web3 js 客户端——或另一个程序——可以直接查看 Solana 账户数据。
这带来了一个非常重要的影响:
在 Solana 中,无法使用重入锁来直接防御只读重入(read only reentrancy)。程序必须暴露标志位,让读取者知道数据是否可靠。
当受害者合约访问了一个显示被篡改数据的 view 函数时,就会发生只读重入。在 Solidity 中,可以通过向 view 函数添加 nonReentrant 修饰符来防御这种情况。然而,在 Solana 中,无法阻止另一个程序查看某个账户中的数据。
不过,Solana 程序仍然可以实现重入守卫所使用的标志位。消费其他程序账户的程序可以检查这些标志,以确认该账户目前是否处于重入状态并且不可信任。
Rust 中没有自定义修饰符
像 onlyOwner 或 nonReentrant 这样的自定义修饰符是 Solidity 的构造,而不是 Rust 中可用的特性。
Rust 或 Anchor 中不可用自定义单位
由于 Solidity 与 Ethereum 联系紧密,它拥有像 ethers 或 wei 这样方便的关键字来作为 Ethereum 的计量单位。不足为奇的是,Rust 中没有定义 LAMPORTS_PER_SOL,但有些令人惊讶的是,Anchor Rust 框架中也没有定义它。不过,它可以在 Solana web3 js 库中使用。
类似地,Solidity 有 days 作为 84,600 秒的便捷别名,但在 Rust/Anchor 中不存在这样的等同物。
Solana 中不存在 “payable” 函数这样的概念。程序从用户那里转走 SOL,而不是用户将 SOL 转给程序
这是下一篇教程的主题。
通过 RareSkills 了解更多
请参阅我们的 Solana 开发课程 获取下一章内容。
原载于 2024 年 3 月 1 日