3.MOVE从入门到实战-可编程Resource-发送者和签署者

Resource 是一种特殊的结构体,可以在Move代码中定义和创建,也可以使用现有的 Resource。因此,我们可以像使用任何其它数据(比如向量或结构体)那样来管理数字资产。

Resource 是Move的关键功能。它使Move变得独一无二,安全且强大。

Move 的主要功能是提供了自定义 Resource 类型。Resource 类型为安全的数字资产编码具提供了丰富的可编程性。 Resource 在Move语言中就是普通的值。它们可以作为数据结构被存储,作为参数被传递给函数,也可以从函数中返回。

Resource 是一种特殊的结构体,可以在Move代码中定义和创建,也可以使用现有的 Resource。因此,我们可以像使用任何其它数据(比如向量或结构体)那样来管理数字资产。

Move 类型系统为 Resource 提供了特殊的安全保证。Resource 永远不能被复制,重用或丢弃。Resource 类型只能由定义该类型的模块创建或销毁。这些检查由 Move 虚拟机通过字节码校验强制执行。Move 虚拟机将拒绝运行任何尚未通过字节码校验的代码。

发送者作为 Signer

在开始使用 Resource 之前,我们需要了解 signer 类型以及这种类型存在的原因。

Signer 是一种原生的类似 Resource 的不可复制的类型,它包含了交易发送者的地址。

Signer 类型代表了发送者权限。换句话说,使用 signer 意味着可以访问发送者的地址和 Resource。它与signature没有直接关系,就 Move VM 而言,它仅表示发送者。

Signer 只有一种 ability: Drop。 abilities 限制符分别是: Copy, Drop, Store 和 Key. Copy - 被修饰的值可以被复制。 Drop - 被修饰的值在作用域结束时可以被丢弃。 Key - 被修饰的值可以作为键值对全局状态进行访问。 Store - 被修饰的值可以被存储到全局状态。

脚本的 Signer

Signer 是原生类型,使用前必须先创建。与vector 这样的原生类型不同,signer 不能直接在代码中创建,但是可以作为脚本参数传递:

script {
    // signer is an owned value
    fun main(account: signer) {
        let _ = account;
    }
}

Signer 参数无需手动将其传递到脚本中,客户端(CLI)会自动将它放入你的脚本中。而且,signer 自始至终都只是引用,虽然标准库中可以访问签名者的实际值,但使用此值的函数是私有的,无法在其他任何地方使用或传递 signer 值。

当前,约定俗成的 signer 类型的变量名是 account

标准库中的 Signer 模块

原生类型离不开原生方法, signer 的原生方法包含在0x1::Signer模块中。这个模块相对比较简单,具体可以参考 Diem 标准库 Signer 模块的实现:

module Std::Signer {
    // Borrows the address of the signer
    // Conceptually, you can think of the `signer` as being a struct wrapper arround an
    // address
    // ```
    // struct Signer has drop { addr: address }
    // ```
    // `borrow_address` borrows this inner field
    native public fun borrow_address(s: &signer): &address;

    // Copies the address of the signer
    public fun address_of(s: &signer): address {
        *borrow_address(s)
    }
    spec address_of {
        pragma opaque;
        aborts_if false;
        ensures result == spec_address_of(s);
    }

    /// Specification version of `Self::address_of`.
    spec native fun spec_address_of(account: signer): address;

}

address_of函数使用更方便,因为它使用了取值运算符来复制地址。

使用起来也非常简单:

script {
    fun main(account: signer) {
        let _ : address = 0x1::Signer::address_of(&account);
    }
}

模块中的 Signer

module M {
    use 0x1::Signer;

    // let's proxy Signer::address_of
    public fun get_address(account: signer): address {
        Signer::address_of(&account)
    }
}

使用&signer作为函数的参数说明该函数正在使用发送者的地址。

引入signer类型的原因之一是要明确显示哪些函数需要发送者权限,哪些不需要。因此,函数不能欺骗用户未经授权访问其 Resource。

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 2022-08-10 10:15
  • 阅读 ( 465 )
  • 学分 ( 18 )
  • 分类:Move

0 条评论

请先 登录 后评论
木头
木头

8 篇文章, 330 学分