ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Sway 断言详解:使用 assert 在智能合约中安全地强制执行运行时条件

Sway 断言详解:使用 assert 在智能合约中安全地强制执行运行时条件 Sway 断言详解使用 assert 在智能合约中安全地强制执行运行时条件【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/swayassert是 Sway 标准库通过 prelude 自动导入到每个程序中的运行时检查函数它接收一个必须求值为 Boolean 的表达式当条件为true时程序继续执行否则虚拟机会回滚revert。本文以 assert 为主线结合 标准库实现 与 官方参考代码系统讲解断言的基本用法、底层 revert 语义、错误码约定并横向对比assert_eq、assert_ne、require、revert等配套函数帮助你写出安全、可预期、便于调试的 Sway 合约代码。什么是断言为不可违背的运行时前提把关断言assertion是一种必须求值为true的条件。在智能合约中断言的目的是阻止不合期望的计算继续执行一旦条件求值为false程序即触发 VM 回滚。例如一个函数只有在满足argument 5时才能正确工作我们可以用断言强制这一前提具体有两种方式当5 argument时强制程序回滚通过额外的代码处理这一异常。对于异常处理可以使用 if 表达式 等控制流结构。因此本文余下内容聚焦于如何让虚拟机安全崩溃revert这是断言机制的核心。Sway 参考文档的 Assertions 章节 将断言族函数分为五个成员函数行为assert检查condition是否为true否则回滚require检查condition是否为true否则记录log一个value并回滚revert以提供的退出码回滚虚拟机assert_eq检查a与b是否相等否则回滚assert_ne检查a与b是否不相等否则回滚assert 的基本用法与典型示例assert无需手动use导入因为它已通过 prelude 中的pub use ::assert::{assert, assert_eq, assert_ne};自动引入每个 Sway 程序。下面是官方参考代码库 lib.sw 中的经典示例一个对两个u64参数做减法运算的函数。fn subtract(a: u64, b: u64) - u64 { assert(b a); a - b }u64是无符号整数无法表示负数。如果b aa - b将产生下溢underflow因此这里的assert(b a)强制保证b必须小于等于a。当条件不满足时虚拟机将回滚杜绝非法运算。关键行为总结条件为true什么都不发生代码继续往下执行条件为false整个交易/调用被回滚状态变更全部撤销。标准库源码视角assert 究竟做了什么assert的实现位于标准库 assert.sw代码非常简短pub fn assert(condition: bool) { if !condition { revert(FAILED_ASSERT_SIGNAL); } }从源码结构可以看出assert的底层只是一个取反判断 调用revert的语法糖对传入条件取反条件为假时以专门的失败信号调用revert。FAILED_ASSERT_SIGNAL定义在 error_signals.sw 中pub const FAILED_ASSERT_SIGNAL 0xffff_ffff_ffff_0004;这个信号值并非随意选取它与兄弟函数共享同一段高位地址空间便于调用方在回滚后区分失败来源信号常量值触发场景FAILED_REQUIRE_SIGNAL0xffff_ffff_ffff_0000require条件为假FAILED_ASSERT_EQ_SIGNAL0xffff_ffff_ffff_0003assert_eq两值不等FAILED_ASSERT_SIGNAL0xffff_ffff_ffff_0004assert条件为假FAILED_ASSERT_NE_SIGNAL0xffff_ffff_ffff_0005assert_ne两值相等REVERT_WITH_LOG_SIGNAL0xffff_ffff_ffff_0006revert_with_log无条件回滚revert 的语义回滚与 panic 两种上下文assert最终调用的revert定义在 revert.swpub fn revert(code: u64) - ! { __revert(code) }注意其返回类型为!never 类型表明调用后函数不会正常返回。根据参考文档 revert.md 的说明revert的行为取决于使用上下文在 predicate谓词 中使用函数会 panic 并使程序崩溃在其他上下文如合约、脚本中使用回滚虚拟机撤销本次执行的所有状态变更。手动强制回滚的示例来自 lib.swfn reverts() { revert(42); }退出码42是调用方自定义的。为了区分不同的回滚原因可以在不同位置使用不同退出码例如fn withdraw(amount: u64, balance: u64) { if amount balance { revert(1); // 余额不足 } // ... }assert 的适用边界与 require 的选择标准库在 assert.sw 的文档注释中明确给出了使用建议对于必须永远为真的运行时条件使用assert对于可能不为真、需要向调用方解释原因的条件改用std::revert::require。两者的差异在于失败时的可观测性assert失败仅以FAILED_ASSERT_SIGNAL回滚不携带任何业务信息require失败先log一个值再以FAILED_REQUIRE_SIGNAL回滚调用方可以通过日志定位失败原因。官方参考 req.sw 给出了require的示例fn subtract(a: u64, b: u64) - u64 { require(b a, b is too large); a - b }当b a时字符串b is too large会被记录logged随后虚拟机回滚。由于require的第二个参数是 泛型T日志值可以是任意类型——字符串、数字、自定义结构体均可例如require(amount 0, 1001); // 用数字作为错误码对应源码实现revert.swpub fn requireT(condition: bool, value: T) { if !condition { log(value); revert(FAILED_REQUIRE_SIGNAL) } }assert_eq 与 assert_ne带日志的相等性断言当断言目标从布尔条件退化为两个值的相等关系时可以使用assert_eq与assert_ne二者在失败时不仅回滚还会将两个输入值分别 log方便离线排查。参考示例lib.swfn compare_eq(a: u64, b: u64) { assert_eq(a, b); // code } fn compare_ne(a: u64, b: u64) { assert_ne(a, b); // code }从源码assert.sw可以看到它们的特征泛型约束T: PartialEq要求类型实现相等性比较 trait失败时log(v1); log(v2);再以对应信号回滚assert_eq失败 →FAILED_ASSERT_EQ_SIGNAL两值不相等assert_ne失败 →FAILED_ASSERT_NE_SIGNAL两值相等在启用experimental_new_encoding特性时额外要求T: AbiEncode以满足新编码格式下 log 的序列化需求见 assert.sw 的#[cfg(experimental_new_encoding true)]分支。编程实践建议综合官方文档与标准库实现使用断言族函数时有几点值得注意区分不可违背的前提与可预期的错误不变量如减法前的b a、除法前的非零除数用assert面向调用方输入校验、需要解释失败原因的场景用require。善用退出码与信号值手动revert(code)时用不同的code区分错误路径标准库自身的断言失败使用0xffff_ffff_ffff_00xx高位信号自定义退出码应避开该区段以免混淆。断言失败即状态回滚无论assert、require还是assert_eq失败都会撤销本次执行的全部存储变更因此断言是保障合约要么全部生效、要么毫无副作用的有力工具。注意 predicate 上下文的特殊性revert在 predicate 中表现为 panic 而非状态回滚涉及 predicate 的代码需单独验证行为。日志辅助调试assert_eq/assert_ne失败时会自动记录两个比较值require会记录业务信息排查链上失败时可优先在这些日志中定位原因。延伸阅读Assertions 章节索引assert 参考文档assert_eq 参考文档assert_ne 参考文档require 参考文档revert 参考文档标准库 prelude 文档标准库断言实现 与 revert/require 实现失败信号常量定义官方断言示例代码 与 require 示例代码【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表