
Sway 区块链开发指南深入理解 Address、ContractId 与 Identity 标识符体系【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/swaySwaysway是 Fuel 区块链的原生智能合约语言。在 Sway 合约开发中Address、ContractId与Identity是三类最基础的标识符类型它们分别标识链上账户、合约和账户或合约的统一主体是转账、鉴权、所有权管理等一切业务的前提。本文以官方文档 identifiers.md 为骨架结合仓库内标准库源码与可运行示例系统讲解这三类标识符的语义差异、底层数据表示、类型转换方法以及访问控制实战用法读完即可在合约中正确选用标识符类型。Sway 地址与 EVM 地址的核心差异官方文档明确指出Sway 中的地址Address与 EVM 地址在用途上相似但存在两大关键区别长度不同Sway 地址长度为32 字节256 位而 EVM 地址只有 20 字节160 位哈希算法不同Sway 地址通过公钥的 SHA-256 哈希计算得出而 EVM 地址使用的是 keccak-256 哈希。Sway 地址 SHA-256(公钥) // 32 字节 EVM 地址 keccak-256(公钥) 的后 20 字节 // 20 字节这一差异意味着Sway 地址天然携带更完整的公钥指纹信息碰撞空间从 160 位提升到 256 位安全性更强同时由于采用 SHA-256地址计算逻辑与 Fuel 虚拟机内部的原生哈希指令保持一致。在仓库的 sway-lib-std/src/hash.sw 中标准库提供了独立的pub fn sha256T(val: T) - b256泛型函数可用于在合约内部对任意可哈希类型计算 SHA-256进而得到这类 32 字节的哈希值。Address账户的唯一标识底层表示对 b256 的结构体包装在 Sway 标准库中Address被定义为一个结构体内部只含一个bits: b256字段address.sw。b256是 Sway 内置的 256 位原始类型恰好对应 32 字节pub struct Address { /// The underlying raw b256 data of the address. bits: b256, }常用方法Address类型提供以下内置方法address.sw方法签名说明bitspub fn bits(self) - b256返回地址底层原始的b256数据zeropub fn zero() - Self返回全零地址未初始化的空地址is_zeropub fn is_zero(self) - bool判断地址是否为零值同时Address实现了PartialEq/Eq基于bits比较、Hash将bits注入哈希器等 trait。注意其Hash实现中is_hash_trivial()返回true——因为底层b256本身就是平凡可哈希的。与其他类型的转换Address与原始b256、字节序列Bytes之间的转换均已在标准库中实现Fromb256 for Address由原始b256构造地址FromAddress for b256取回地址的b256数据TryFromBytes for Address由Bytes尝试构造地址仅当字节长度恰好为 32 时成功否则返回NoneIntoBytes for Address将地址转为 32 字节的Bytes。ContractId合约的唯一标识官方文档特别强调合约不使用地址而是用合约 IDContract ID唯一标识。合约 ID 同样为 32 字节其计算方式定义在 Fuel 协议规范中根据原始文档链接指向的协议说明。这一设计使得账户与合约在链上拥有彼此独立的命名空间避免两类主体的标识符发生冲突。标准库中的 ContractId 与Address结构完全对称——同样是对b256的结构体包装同样实现了bits/zero/is_zero、PartialEq/Eq、Hash以及Fromb256/FromContractId/TryFromBytes/IntoBytes等 trait。ContractId独有的方法是this()contract_id.sw它通过内联汇编读取帧指针fp寄存器来返回当前正在执行的合约自身 ID典型用法是合约查询我是谁pub fn this() - ContractId { ContractId::from(asm() { fp: b256 }) }注意this()的文档注释提醒如果在外部上下文如脚本或谓词中调用它不会返回合约 ID而是返回指向交易 ID 的指针因此在合约外部使用时需要特别小心。Identity统一 Address 与 ContractId 的枚举类型Identity是 Sway 中用于以统一方式处理地址与合约交互的封装类型identity.sw它是一个枚举恰好两个变体pub enum Identity { Address: Address, ContractId: ContractId, }核心方法方法签名说明as_addresspub fn as_address(self) - OptionAddress若为地址变体则返回Some(Address)否则Noneas_contract_idpub fn as_contract_id(self) - OptionContractId若为合约变体则返回Some(ContractId)否则Noneis_addresspub fn is_address(self) - bool判断是否为地址变体is_contract_idpub fn is_contract_id(self) - bool判断是否为合约变体bitspub fn bits(self) - b256返回底层b256数据无论何种变体哈希与比较语义PartialEq仅当同为地址变体且地址相等或同为合约变体且 ID 相等时返回true跨变体比较恒为falseHash哈希时将枚举标签0_u8地址或1_u8合约连同底层数据一起注入哈希器identity.sw。其is_hash_trivial()返回false源码中的 TODO 注释解释了原因枚举标签在内存中以u64存储、但以u8参与哈希因此不满足平凡可哈希的条件。这一设计让开发者可以把可能是账户、可能是合约的调用方统一存储与比较是 SRC-5 所有权标准等场景的基础。类型转换实操b256 ↔ Address/ContractId ↔ Identity仓库的示例库 converting_types/src/identity.sw 给出了完整、可直接照搬的转换代码。从 b256 构造标识符let b256_address: b256 0x000000000000000000000000000000000000000000000000000000000000002A; // b256 - Address / ContractId let address_from_b256: Address Address::from(b256_address); let contract_id_from_b256: ContractId ContractId::from(b256_address); // b256 - Identity let identity_from_b256: Identity Identity::Address(Address::from(b256_address)); let identity_from_address: Identity Identity::Address(address_from_b256); let identity_from_contract_id: Identity Identity::ContractId(contract_id_from_b256);从 Identity 取回具体类型通过match将Identity解包为Address或ContractIdmatch my_identity { Identity::Address(address) log(address), Identity::ContractId(contract_id) log(contract_id), };从标识符取回 b256let b256_from_address: b256 address.into(); let b256_from_contract_id: b256 contract_id.into();地址常量示例examples/msg_sender/src/main.sw 展示了如何把 32 字节的十六进制字面量直接构造为地址常量const OWNER Address::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);实战应用msg_sender 与基于 Identity 的访问控制msg_sender获取调用方身份标准库 auth.sw 中的msg_sender()是获取谁在调用我的标准入口其返回类型正是ResultIdentity, AuthErrorpub fn msg_sender() - ResultIdentity, AuthError { if caller_is_external() { match caller_address() { ... } // 外部调用返回地址 } else { Ok(Identity::ContractId(caller_contract_id())) // 内部调用返回合约 ID } }它根据调用方是外部脚本/谓词还是内部另一个合约自动返回Identity::Address或Identity::ContractId让调用方身份判断与标识符类型天然统一。用 Identity 实现访问控制examples/identity/src/main.sw 是官方示例合约其存储直接以Identity作为 owner 类型storage { owner: Identity Identity::ContractId(ContractId::zero()), } fn access_control_with_identity() { let sender msg_sender().unwrap(); require( sender storage.owner.read(), MyError::UnauthorizedUser(sender), ); }而 examples/msg_sender/src/main.sw 展示了只允许账户地址、拒绝合约调用的鉴权模式fn receive(field_1: u64) - bool { let sender msg_sender().unwrap(); if let Identity::Address(addr) sender { assert(addr OWNER); } else { revert(0); } true }SRC-5 所有权标准中的 Identityexamples/ownership/src/main.sw 给出了 SRC-5 Ownership 标准骨架其中Identity被直接嵌入所有权状态pub enum State { Uninitialized: (), Initialized: Identity, Revoked: (), } storage { owner: Ownership Ownership::initialized(Identity::Address(Address::zero())), }由于Identity既能承载账户地址也能承载合约 ID所有权可以方便地授予 EOA 或另一合约这正是标准库选择Identity而非单一Address作为所有权主体的原因。小结与选型建议类型标识对象字节数底层数据典型用途Address链上账户32SHA-256 公钥哈希b256账户鉴权、交易输入所有者ContractId链上合约32协议规范定义计算b256合约自身标识、跨合约调用Identity账户或合约32内部枚举b256统一主体存储、所有权、msg_sender返回开发建议当业务主体只可能是账户时直接使用Address当业务主体只可能是合约时如记录由哪个合约铸造使用ContractId并可用ContractId::this()获取当前合约自身当主体可能是账户也可能是合约如所有权、授权方、调用方时一律使用Identity配合msg_sender()与match解包即可优雅处理两种调用场景。在底层三者都可与b256互转32 字节、SHA-256 哈希体系这也意味着它们在存储、哈希与序列化上的行为高度一致可以放心用于storage、log与跨合约参数传递。【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考