ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Sway 区块链类型完全指南:Address、ContractId 与 Identity 的深度解析

Sway 区块链类型完全指南:Address、ContractId 与 Identity 的深度解析 Sway 区块链类型完全指南Address、ContractId 与 Identity 的深度解析【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/swaySway 是一门为区块链而生的语言其标准库sway-lib-std为智能合约开发提供了专门设计的核心类型Address、ContractId与Identity。本文以 docs/book/src/basics/blockchain_types.md 为骨架结合标准库源码与 examples/identity 完整示例系统讲解这三种类型的实现原理、显式转换规则、合约内获取自身 ID 的方法以及基于Identity的通用访问控制实战方案。读完本文你将能够准确区分地址与合约 ID 的语义差异熟练进行类型转换并独立实现同时兼容账户与合约调用者的权限校验逻辑。为什么 Sway 需要专属的区块链类型Sway 从根本上就是一门面向区块链的语言因此它提供了一组为区块链场景量身定制的类型。这些类型通过标准库提供一方面增加了类型安全type-safety另一方面也让开发者的意图表达更加清晰。与 EVM 生态不同SwayFuel 生态对地址与合约进行了严格的语义区分Address永远不会指向已部署的智能合约。它可以是公钥哈希相当于 EVM 中的外部账户 externally owned account也可以是某个 predicate 的哈希。地址拥有 UTXO。ContractId才是合约的唯一、确定性标识符类似 EVM 中合约的地址。合约不能拥有 UTXO但可以拥有资产。这种区分避免了 EVM 中一个地址既可能是 EOA 又可能是合约的歧义从类型系统层面杜绝了一类常见的审计风险。Address类型b256 的类型安全包装结构定义与本质Address是对原始b256类型的一个类型安全包装结构体。其真实定义位于 sway-lib-std/src/address.sw/// The Address type, a struct wrapper around the inner b256 value. pub struct Address { /// The underlying raw b256 data of the address. bits: b256, }文档中的写法pub struct Address { value: b256 }是简化示意实际字段名为bits。包装层带来了以下能力bits()取出底层原始b256数据zero()/is_zero()构造或判断零值地址PartialEq/Eq基于b256逐位比较实现相等性Hashis_hash_trivial() - true可平凡哈希用于存储键、映射等场景。与 b256 的显式转换在b256与Address之间转换必须显式进行不能隐式互转let my_number: b256 0x000000000000000000000000000000000000000000000000000000000000002A; let my_address: Address Address::from(my_number); let forty_two: b256 my_address.into();底层实现中Fromb256 for Address直接包裹原始数据FromAddress for b256调用address.bits()取出数据见 address.sw。此外标准库还提供了与Bytes的互转TryFromBytes for Address会先校验长度是否为 32 字节不满足则返回None见 address.sw这为序列化/反序列化场景提供了安全入口。ContractId类型合约的唯一标识结构定义与本质ContractId同样是对b256的类型安全包装其实现位于 sway-lib-std/src/contract_id.sw/// The ContractId type, a struct wrapper around the inner b256 value. pub struct ContractId { /// The underlying raw b256 data of the contract id. bits: b256, }一个合约的 ID 是唯一且确定性的标识符由合约的字节码根bytecode root推导而来这与 predicate 地址的推导方式类似。合约无法拥有 UTXO但可以持有资产例如通过mint铸造的资产归属于铸造合约的ContractId。与 b256 的显式转换转换规则与Address完全对称同样要求显式进行let my_number: b256 0x000000000000000000000000000000000000000000000000000000000000002A; let my_contract_id: ContractId ContractId::from(my_number); let forty_two: b256 my_contract_id.into();实现细节见 contract_id.sw同样提供Fromb256/FromContractId双向转换以及带长度校验的TryFromBytes/IntoBytes。获取当前合约的ContractIdContractId::this()在合约内部internal context可以通过ContractId::this()获取当前正在执行合约的 IDimpl MyContract for Contract { fn foo() { let this_contract_id: ContractId ContractId::this(); } }其底层实现直接读取帧指针寄存器fp并包装为ContractId见 contract_id.swpub fn this() - ContractId { ContractId::from(asm() { fp: b256 }) }注意使用前提该函数只有在内部上下文即合约方法被调用时才能正确返回当前合约 ID。源码注释明确指出如果在外部上下文调用返回的将不是合约 ID 而是指向交易 IDTransaction Id的指针包装。典型用法是在合约内查询自己的资产例如AssetId::default(this_contract)配合mint铸造并转账给自己的资产见 contract_id.sw 中的标准库文档示例。Identity类型统一 Address 与 ContractId 的枚举定义与设计动机Identity是一个枚举允许统一处理Address和ContractId两种类型。这在两者皆可的场景下非常有用例如接收来自某个已识别发送者的资金但调用方不关心发送者究竟是账户地址还是合约。其真实定义位于 sway-lib-std/src/identity.swpub enum Identity { Address: Address, ContractId: ContractId, }Identity同时实现了PartialEq/Eq仅当同为Address或同为ContractId时才可能相等、Hash哈希时先写入 1 字节的枚举标签0_u8/1_u8再哈希内部数据见 identity.sw并提供了丰富的辅助方法方法签名说明as_address()- OptionAddress底层为Address时返回Some否则Noneas_contract_id()- OptionContractId底层为ContractId时返回Some否则Noneis_address()- bool是否为Address变体is_contract_id()- bool是否为ContractId变体bits()- b256取出底层原始b256数据这些方法的完整实现见 identity.sw。显式构造与 match 解构向Identity的转换必须显式完成通常通过枚举变体构造// 来自 examples/identity/src/main.sw 的 cast_to_identity 锚点 let raw_address: b256 0xddec0e7e6a9a4a4e3e57d08d080d71a299c628a46bc609aab4627695679421ca; let my_identity: Identity Identity::Address(Address::from(raw_address));反向解构则通过match表达式完成。既可以安全提取内部值也可以针对不同变体执行差异化逻辑。将Identity还原为ContractId不匹配则回滚// 来自 examples/identity/src/main.sw 的 identity_to_contract_id 锚点 let my_contract_id: ContractId match my_identity { Identity::ContractId(identity) identity, _ revert(0), };根据变体执行不同分支// 来自 examples/identity/src/main.sw 的 different_executions 锚点 match my_identity { Identity::Address(address) takes_address(address), Identity::ContractId(contract_id) takes_contract_id(contract_id), };实战基于Identity的访问控制Identity最常见的用途是访问控制access control。它独有的优势在于同一个权限模型中ContractId和Address可以同时获得访问权限——即无论是外部账户还是其他合约调用只要其Identity匹配授权名单即可通过。examples/identity 是一个完整的可运行合约示例它首先在存储中声明以Identity为类型的owner// 来自 examples/identity/src/main.sw storage { owner: Identity Identity::ContractId(ContractId::zero()), }然后通过msg_sender()获取调用者身份并与存储中的owner比对// 来自 examples/identity/src/main.sw 的 access_control_with_identity 锚点 #[storage(read)] fn access_control_with_identity() { let sender msg_sender().unwrap(); require( sender storage .owner .read(), MyError::UnauthorizedUser(sender), ); }其中MyError::UnauthorizedUser携带了实际调用者的Identity作为错误载荷便于链上诊断见 errors.swpub enum MyError { UnauthorizedUser: Identity, }msg_sender()的底层语义msg_sender()定义于 sway-lib-std/src/auth.sw它返回ResultIdentity, AuthError其内部逻辑为pub fn msg_sender() - ResultIdentity, AuthError { if caller_is_external() { match caller_address() { Err(err) Err(err), Ok(owner) Ok(Identity::Address(owner)), } } else { // Get callers ContractId. Ok(Identity::ContractId(caller_contract_id())) } }若调用者来自外部脚本/账户尝试确定交易输入的共同所有者成功则返回Identity::Address若调用者是合约则返回Identity::ContractId。这正解释了为什么基于Identity的访问控制天然覆盖两类调用者——msg_sender()在协议层面就把两种身份统一成了同一种类型。实践中常见的写法是结合if let模式匹配例如 examples/msg_sender 中先取出Identity再解构Address变体与常量OWNER比较。三种类型的选择建议场景推荐类型理由记录账户/外部调用者验证签名归属Address语义明确为账户或 predicate拥有 UTXO引用某个已部署合约、管理合约自身资产ContractId唯一确定性标识符可在内部通过ContractId::this()获取权限校验、接收方账户或合约皆可Identity统一两类身份配合msg_sender()与match天然适配访问控制需要原始 32 字节数据参与哈希/存储键b256配合bits()显式取出一切包装类型的底层载体需要再次强调所有转换b256↔Address、b256↔ContractId、任意类型 →Identity都必须显式书写这是 Sway 类型系统刻意设计的约束目的是在编译期强制开发者明确表达意图避免跨类别身份的隐式混淆。延伸阅读三种类型在标准库中的完整实现address.sw、contract_id.sw、identity.sw完整可运行的访问控制合约示例examples/identity/src/main.sw其依赖声明见 examples/identity/Forc.tomlmsg_sender()与调用者鉴权体系sway-lib-std/src/auth.swpredicate 地址与Address的关系predicates 文档【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表